1/* GENERATED SOURCE. DO NOT MODIFY. */
2// © 2016 and later: Unicode, Inc. and others.
3// License & terms of use: http://www.unicode.org/copyright.html#License
4/*
5******************************************************************************
6* Copyright (C) 1996-2010, International Business Machines Corporation and   *
7* others. All Rights Reserved.                                               *
8******************************************************************************
9*/
10
11package android.icu.impl;
12
13import java.io.DataOutputStream;
14import java.io.IOException;
15import java.io.OutputStream;
16import java.util.Arrays;
17
18import android.icu.lang.UCharacter;
19import android.icu.text.UTF16;
20
21/**
22 * Builder class to manipulate and generate a trie.
23 * This is useful for ICU data in primitive types.
24 * Provides a compact way to store information that is indexed by Unicode
25 * values, such as character properties, types, keyboard values, etc. This is
26 * very useful when you have a block of Unicode data that contains significant
27 * values while the rest of the Unicode data is unused in the application or
28 * when you have a lot of redundance, such as where all 21,000 Han ideographs
29 * have the same value.  However, lookup is much faster than a hash table.
30 * A trie of any primitive data type serves two purposes:
31 * <UL type = round>
32 *     <LI>Fast access of the indexed values.
33 *     <LI>Smaller memory footprint.
34 * </UL>
35 * This is a direct port from the ICU4C version
36 * @author             Syn Wee Quek
37 * @hide Only a subset of ICU is exposed in Android
38 */
39public class IntTrieBuilder extends TrieBuilder
40{
41    // public constructor ----------------------------------------------
42
43    /**
44     * Copy constructor
45     */
46    public IntTrieBuilder(IntTrieBuilder table)
47    {
48        super(table);
49        m_data_ = new int[m_dataCapacity_];
50        System.arraycopy(table.m_data_, 0, m_data_, 0, m_dataLength_);
51        m_initialValue_ = table.m_initialValue_;
52        m_leadUnitValue_ = table.m_leadUnitValue_;
53    }
54
55    /**
56     * Constructs a build table
57     * @param aliasdata data to be filled into table
58     * @param maxdatalength maximum data length allowed in table
59     * @param initialvalue inital data value
60     * @param latin1linear is latin 1 to be linear
61     */
62    public IntTrieBuilder(int aliasdata[], int maxdatalength,
63                          int initialvalue, int leadunitvalue,
64                          boolean latin1linear)
65    {
66        super();
67        if (maxdatalength < DATA_BLOCK_LENGTH || (latin1linear
68                                                  && maxdatalength < 1024)) {
69            throw new IllegalArgumentException(
70                                               "Argument maxdatalength is too small");
71        }
72
73        if (aliasdata != null) {
74            m_data_ = aliasdata;
75        }
76        else {
77            m_data_ = new int[maxdatalength];
78        }
79
80        // preallocate and reset the first data block (block index 0)
81        int j = DATA_BLOCK_LENGTH;
82
83        if (latin1linear) {
84            // preallocate and reset the first block (number 0) and Latin-1
85            // (U+0000..U+00ff) after that made sure above that
86            // maxDataLength >= 1024
87            // set indexes to point to consecutive data blocks
88            int i = 0;
89            do {
90                // do this at least for trie->index[0] even if that block is
91                // only partly used for Latin-1
92                m_index_[i ++] = j;
93                j += DATA_BLOCK_LENGTH;
94            } while (i < (256 >> SHIFT_));
95        }
96
97        m_dataLength_ = j;
98        // reset the initially allocated blocks to the initial value
99        Arrays.fill(m_data_, 0, m_dataLength_, initialvalue);
100        m_initialValue_ = initialvalue;
101        m_leadUnitValue_ = leadunitvalue;
102        m_dataCapacity_ = maxdatalength;
103        m_isLatin1Linear_ = latin1linear;
104        m_isCompacted_ = false;
105    }
106
107    // public methods -------------------------------------------------------
108
109    /*public final void print()
110      {
111      int i = 0;
112      int oldvalue = m_index_[i];
113      int count = 0;
114      System.out.println("index length " + m_indexLength_
115      + " --------------------------");
116      while (i < m_indexLength_) {
117      if (m_index_[i] != oldvalue) {
118      System.out.println("index has " + count + " counts of "
119      + Integer.toHexString(oldvalue));
120      count = 0;
121      oldvalue = m_index_[i];
122      }
123      count ++;
124      i ++;
125      }
126      System.out.println("index has " + count + " counts of "
127      + Integer.toHexString(oldvalue));
128      i = 0;
129      oldvalue = m_data_[i];
130      count = 0;
131      System.out.println("data length " + m_dataLength_
132      + " --------------------------");
133      while (i < m_dataLength_) {
134      if (m_data_[i] != oldvalue) {
135      if ((oldvalue & 0xf1000000) == 0xf1000000) {
136      int temp = oldvalue & 0xffffff;
137      temp += 0x320;
138      oldvalue = 0xf1000000 | temp;
139      }
140      if ((oldvalue & 0xf2000000) == 0xf2000000) {
141      int temp = oldvalue & 0xffffff;
142      temp += 0x14a;
143      oldvalue = 0xf2000000 | temp;
144      }
145      System.out.println("data has " + count + " counts of "
146      + Integer.toHexString(oldvalue));
147      count = 0;
148      oldvalue = m_data_[i];
149      }
150      count ++;
151      i ++;
152      }
153      if ((oldvalue & 0xf1000000) == 0xf1000000) {
154      int temp = oldvalue & 0xffffff;
155      temp += 0x320;
156      oldvalue = 0xf1000000 | temp;
157      }
158      if ((oldvalue & 0xf2000000) == 0xf2000000) {
159      int temp = oldvalue & 0xffffff;
160      temp += 0x14a;
161      oldvalue = 0xf2000000 | temp;
162      }
163      System.out.println("data has " + count + " counts of "
164      + Integer.toHexString(oldvalue));
165      }
166    */
167    /**
168     * Gets a 32 bit data from the table data
169     * @param ch codepoint which data is to be retrieved
170     * @return the 32 bit data
171     */
172    public int getValue(int ch)
173    {
174        // valid, uncompacted trie and valid c?
175        if (m_isCompacted_ || ch > UCharacter.MAX_VALUE || ch < 0) {
176            return 0;
177        }
178
179        int block = m_index_[ch >> SHIFT_];
180        return m_data_[Math.abs(block) + (ch & MASK_)];
181    }
182
183    /**
184     * Get a 32 bit data from the table data
185     * @param ch  code point for which data is to be retrieved.
186     * @param inBlockZero  Output parameter, inBlockZero[0] returns true if the
187     *                      char maps into block zero, otherwise false.
188     * @return the 32 bit data value.
189     */
190    public int getValue(int ch, boolean [] inBlockZero)
191    {
192        // valid, uncompacted trie and valid c?
193        if (m_isCompacted_ || ch > UCharacter.MAX_VALUE || ch < 0) {
194            if (inBlockZero != null) {
195                inBlockZero[0] = true;
196            }
197            return 0;
198        }
199
200        int block = m_index_[ch >> SHIFT_];
201        if (inBlockZero != null) {
202            inBlockZero[0] = (block == 0);
203        }
204        return m_data_[Math.abs(block) + (ch & MASK_)];
205    }
206
207
208    /**
209     * Sets a 32 bit data in the table data
210     * @param ch codepoint which data is to be set
211     * @param value to set
212     * @return true if the set is successful, otherwise
213     *              if the table has been compacted return false
214     */
215    public boolean setValue(int ch, int value)
216    {
217        // valid, uncompacted trie and valid c?
218        if (m_isCompacted_ || ch > UCharacter.MAX_VALUE || ch < 0) {
219            return false;
220        }
221
222        int block = getDataBlock(ch);
223        if (block < 0) {
224            return false;
225        }
226
227        m_data_[block + (ch & MASK_)] = value;
228        return true;
229    }
230
231    /**
232     * Serializes the build table with 32 bit data
233     * @param datamanipulate builder raw fold method implementation
234     * @param triedatamanipulate result trie fold method
235     * @return a new trie
236     */
237    public IntTrie serialize(TrieBuilder.DataManipulate datamanipulate,
238                             Trie.DataManipulate triedatamanipulate)
239    {
240        if (datamanipulate == null) {
241            throw new IllegalArgumentException("Parameters can not be null");
242        }
243        // fold and compact if necessary, also checks that indexLength is
244        // within limits
245        if (!m_isCompacted_) {
246            // compact once without overlap to improve folding
247            compact(false);
248            // fold the supplementary part of the index array
249            fold(datamanipulate);
250            // compact again with overlap for minimum data array length
251            compact(true);
252            m_isCompacted_ = true;
253        }
254        // is dataLength within limits?
255        if (m_dataLength_ >= MAX_DATA_LENGTH_) {
256            throw new ArrayIndexOutOfBoundsException("Data length too small");
257        }
258
259        char index[] = new char[m_indexLength_];
260        int data[] = new int[m_dataLength_];
261        // write the index (stage 1) array and the 32-bit data (stage 2) array
262        // write 16-bit index values shifted right by INDEX_SHIFT_
263        for (int i = 0; i < m_indexLength_; i ++) {
264            index[i] = (char)(m_index_[i] >>> INDEX_SHIFT_);
265        }
266        // write 32-bit data values
267        System.arraycopy(m_data_, 0, data, 0, m_dataLength_);
268
269        int options = SHIFT_ | (INDEX_SHIFT_ << OPTIONS_INDEX_SHIFT_);
270        options |= OPTIONS_DATA_IS_32_BIT_;
271        if (m_isLatin1Linear_) {
272            options |= OPTIONS_LATIN1_IS_LINEAR_;
273        }
274        return new IntTrie(index, data, m_initialValue_, options,
275                           triedatamanipulate);
276    }
277
278
279    /**
280     * Serializes the build table to an output stream.
281     *
282     * Compacts the build-time trie after all values are set, and then
283     * writes the serialized form onto an output stream.
284     *
285     * After this, this build-time Trie can only be serialized again and/or closed;
286     * no further values can be added.
287     *
288     * This function is the rough equivalent of utrie_seriaize() in ICU4C.
289     *
290     * @param os the output stream to which the seriaized trie will be written.
291     *         If nul, the function still returns the size of the serialized Trie.
292     * @param reduceTo16Bits If true, reduce the data size to 16 bits.  The resulting
293     *         serialized form can then be used to create a CharTrie.
294     * @param datamanipulate builder raw fold method implementation
295     * @return the number of bytes written to the output stream.
296     */
297     public int serialize(OutputStream os, boolean reduceTo16Bits,
298            TrieBuilder.DataManipulate datamanipulate)  throws IOException {
299         if (datamanipulate == null) {
300             throw new IllegalArgumentException("Parameters can not be null");
301         }
302
303         // fold and compact if necessary, also checks that indexLength is
304         // within limits
305         if (!m_isCompacted_) {
306             // compact once without overlap to improve folding
307             compact(false);
308             // fold the supplementary part of the index array
309             fold(datamanipulate);
310             // compact again with overlap for minimum data array length
311             compact(true);
312             m_isCompacted_ = true;
313         }
314
315         // is dataLength within limits?
316         int length;
317         if (reduceTo16Bits) {
318             length = m_dataLength_ + m_indexLength_;
319         } else {
320             length = m_dataLength_;
321         }
322         if (length >= MAX_DATA_LENGTH_) {
323             throw new ArrayIndexOutOfBoundsException("Data length too small");
324         }
325
326         //  struct UTrieHeader {
327         //      int32_t   signature;
328         //      int32_t   options  (a bit field)
329         //      int32_t   indexLength
330         //      int32_t   dataLength
331         length = Trie.HEADER_LENGTH_ + 2*m_indexLength_;
332         if(reduceTo16Bits) {
333             length+=2*m_dataLength_;
334         } else {
335             length+=4*m_dataLength_;
336         }
337
338         if (os == null) {
339             // No output stream.  Just return the length of the serialized Trie, in bytes.
340             return length;
341         }
342
343         DataOutputStream dos = new DataOutputStream(os);
344         dos.writeInt(Trie.HEADER_SIGNATURE_);
345
346         int options = Trie.INDEX_STAGE_1_SHIFT_ | (Trie.INDEX_STAGE_2_SHIFT_<<Trie.HEADER_OPTIONS_INDEX_SHIFT_);
347         if(!reduceTo16Bits) {
348             options |= Trie.HEADER_OPTIONS_DATA_IS_32_BIT_;
349         }
350         if(m_isLatin1Linear_) {
351             options |= Trie.HEADER_OPTIONS_LATIN1_IS_LINEAR_MASK_;
352         }
353         dos.writeInt(options);
354
355         dos.writeInt(m_indexLength_);
356         dos.writeInt(m_dataLength_);
357
358         /* write the index (stage 1) array and the 16/32-bit data (stage 2) array */
359         if(reduceTo16Bits) {
360             /* write 16-bit index values shifted right by UTRIE_INDEX_SHIFT, after adding indexLength */
361             for (int i=0; i<m_indexLength_; i++) {
362                 int v = (m_index_[i] + m_indexLength_) >>> Trie.INDEX_STAGE_2_SHIFT_;
363                 dos.writeChar(v);
364             }
365
366             /* write 16-bit data values */
367             for(int i=0; i<m_dataLength_; i++) {
368                 int v = m_data_[i] & 0x0000ffff;
369                 dos.writeChar(v);
370             }
371         } else {
372             /* write 16-bit index values shifted right by UTRIE_INDEX_SHIFT */
373             for (int i=0; i<m_indexLength_; i++) {
374                 int v = (m_index_[i]) >>> Trie.INDEX_STAGE_2_SHIFT_;
375                 dos.writeChar(v);
376             }
377
378             /* write 32-bit data values */
379             for(int i=0; i<m_dataLength_; i++) {
380                 dos.writeInt(m_data_[i]);
381             }
382        }
383
384         return length;
385
386    }
387
388
389    /**
390     * Set a value in a range of code points [start..limit].
391     * All code points c with start &lt;= c &lt; limit will get the value if
392     * overwrite is true or if the old value is 0.
393     * @param start the first code point to get the value
394     * @param limit one past the last code point to get the value
395     * @param value the value
396     * @param overwrite flag for whether old non-initial values are to be
397     *        overwritten
398     * @return false if a failure occurred (illegal argument or data array
399     *               overrun)
400     */
401    public boolean setRange(int start, int limit, int value,
402                            boolean overwrite)
403    {
404        // repeat value in [start..limit[
405        // mark index values for repeat-data blocks by setting bit 31 of the
406        // index values fill around existing values if any, if(overwrite)
407
408        // valid, uncompacted trie and valid indexes?
409        if (m_isCompacted_ || start < UCharacter.MIN_VALUE
410            || start > UCharacter.MAX_VALUE || limit < UCharacter.MIN_VALUE
411            || limit > (UCharacter.MAX_VALUE + 1) || start > limit) {
412            return false;
413        }
414
415        if (start == limit) {
416            return true; // nothing to do
417        }
418
419        if ((start & MASK_) != 0) {
420            // set partial block at [start..following block boundary[
421            int block = getDataBlock(start);
422            if (block < 0) {
423                return false;
424            }
425
426            int nextStart = (start + DATA_BLOCK_LENGTH) & ~MASK_;
427            if (nextStart <= limit) {
428                fillBlock(block, start & MASK_, DATA_BLOCK_LENGTH,
429                          value, overwrite);
430                start = nextStart;
431            }
432            else {
433                fillBlock(block, start & MASK_, limit & MASK_,
434                          value, overwrite);
435                return true;
436            }
437        }
438
439        // number of positions in the last, partial block
440        int rest = limit & MASK_;
441
442        // round down limit to a block boundary
443        limit &= ~MASK_;
444
445        // iterate over all-value blocks
446        int repeatBlock = 0;
447        if (value == m_initialValue_) {
448            // repeatBlock = 0; assigned above
449        }
450        else {
451            repeatBlock = -1;
452        }
453        while (start < limit) {
454            // get index value
455            int block = m_index_[start >> SHIFT_];
456            if (block > 0) {
457                // already allocated, fill in value
458                fillBlock(block, 0, DATA_BLOCK_LENGTH, value, overwrite);
459            }
460            else if (m_data_[-block] != value && (block == 0 || overwrite)) {
461                // set the repeatBlock instead of the current block 0 or range
462                // block
463                if (repeatBlock >= 0) {
464                    m_index_[start >> SHIFT_] = -repeatBlock;
465                }
466                else {
467                    // create and set and fill the repeatBlock
468                    repeatBlock = getDataBlock(start);
469                    if (repeatBlock < 0) {
470                        return false;
471                    }
472
473                    // set the negative block number to indicate that it is a
474                    // repeat block
475                    m_index_[start >> SHIFT_] = -repeatBlock;
476                    fillBlock(repeatBlock, 0, DATA_BLOCK_LENGTH, value, true);
477                }
478            }
479
480            start += DATA_BLOCK_LENGTH;
481        }
482
483        if (rest > 0) {
484            // set partial block at [last block boundary..limit[
485            int block = getDataBlock(start);
486            if (block < 0) {
487                return false;
488            }
489            fillBlock(block, 0, rest, value, overwrite);
490        }
491
492        return true;
493    }
494
495    // protected data member ------------------------------------------------
496
497    protected int m_data_[];
498    protected int m_initialValue_;
499
500    //  private data member ------------------------------------------------
501
502    private int m_leadUnitValue_;
503
504    // private methods ------------------------------------------------------
505
506    private int allocDataBlock()
507    {
508        int newBlock = m_dataLength_;
509        int newTop = newBlock + DATA_BLOCK_LENGTH;
510        if (newTop > m_dataCapacity_) {
511            // out of memory in the data array
512            return -1;
513        }
514        m_dataLength_ = newTop;
515        return newBlock;
516    }
517
518    /**
519     * No error checking for illegal arguments.
520     * @param ch codepoint to look for
521     * @return -1 if no new data block available (out of memory in data array)
522     */
523    private int getDataBlock(int ch)
524    {
525        ch >>= SHIFT_;
526        int indexValue = m_index_[ch];
527        if (indexValue > 0) {
528            return indexValue;
529        }
530
531        // allocate a new data block
532        int newBlock = allocDataBlock();
533        if (newBlock < 0) {
534            // out of memory in the data array
535            return -1;
536        }
537        m_index_[ch] = newBlock;
538
539        // copy-on-write for a block from a setRange()
540        System.arraycopy(m_data_, Math.abs(indexValue), m_data_, newBlock,
541                         DATA_BLOCK_LENGTH << 2);
542        return newBlock;
543    }
544
545    /**
546     * Compact a folded build-time trie.
547     * The compaction
548     * - removes blocks that are identical with earlier ones
549     * - overlaps adjacent blocks as much as possible (if overlap == true)
550     * - moves blocks in steps of the data granularity
551     * - moves and overlaps blocks that overlap with multiple values in the overlap region
552     *
553     * It does not
554     * - try to move and overlap blocks that are not already adjacent
555     * @param overlap flag
556     */
557    private void compact(boolean overlap)
558    {
559        if (m_isCompacted_) {
560            return; // nothing left to do
561        }
562
563        // compaction
564        // initialize the index map with "block is used/unused" flags
565        findUnusedBlocks();
566
567        // if Latin-1 is preallocated and linear, then do not compact Latin-1
568        // data
569        int overlapStart = DATA_BLOCK_LENGTH;
570        if (m_isLatin1Linear_ && SHIFT_ <= 8) {
571            overlapStart += 256;
572        }
573
574        int newStart = DATA_BLOCK_LENGTH;
575        int i;
576        for (int start = newStart; start < m_dataLength_;) {
577            // start: index of first entry of current block
578            // newStart: index where the current block is to be moved
579            //           (right after current end of already-compacted data)
580            // skip blocks that are not used
581            if (m_map_[start >>> SHIFT_] < 0) {
582                // advance start to the next block
583                start += DATA_BLOCK_LENGTH;
584                // leave newStart with the previous block!
585                continue;
586            }
587            // search for an identical block
588            if (start >= overlapStart) {
589                i = findSameDataBlock(m_data_, newStart, start,
590                                          overlap ? DATA_GRANULARITY_ : DATA_BLOCK_LENGTH);
591                if (i >= 0) {
592                    // found an identical block, set the other block's index
593                    // value for the current block
594                    m_map_[start >>> SHIFT_] = i;
595                    // advance start to the next block
596                    start += DATA_BLOCK_LENGTH;
597                    // leave newStart with the previous block!
598                    continue;
599                }
600            }
601            // see if the beginning of this block can be overlapped with the
602            // end of the previous block
603            if(overlap && start>=overlapStart) {
604                /* look for maximum overlap (modulo granularity) with the previous, adjacent block */
605                for(i=DATA_BLOCK_LENGTH-DATA_GRANULARITY_;
606                    i>0 && !equal_int(m_data_, newStart-i, start, i);
607                    i-=DATA_GRANULARITY_) {}
608            } else {
609                i=0;
610            }
611            if (i > 0) {
612                // some overlap
613                m_map_[start >>> SHIFT_] = newStart - i;
614                // move the non-overlapping indexes to their new positions
615                start += i;
616                for (i = DATA_BLOCK_LENGTH - i; i > 0; -- i) {
617                    m_data_[newStart ++] = m_data_[start ++];
618                }
619            }
620            else if (newStart < start) {
621                // no overlap, just move the indexes to their new positions
622                m_map_[start >>> SHIFT_] = newStart;
623                for (i = DATA_BLOCK_LENGTH; i > 0; -- i) {
624                    m_data_[newStart ++] = m_data_[start ++];
625                }
626            }
627            else { // no overlap && newStart==start
628                m_map_[start >>> SHIFT_] = start;
629                newStart += DATA_BLOCK_LENGTH;
630                start = newStart;
631            }
632        }
633        // now adjust the index (stage 1) table
634        for (i = 0; i < m_indexLength_; ++ i) {
635            m_index_[i] = m_map_[Math.abs(m_index_[i]) >>> SHIFT_];
636        }
637        m_dataLength_ = newStart;
638    }
639
640    /**
641     * Find the same data block
642     * @param data array
643     * @param dataLength
644     * @param otherBlock
645     * @param step
646     */
647    private static final int findSameDataBlock(int data[], int dataLength,
648                                               int otherBlock, int step)
649    {
650        // ensure that we do not even partially get past dataLength
651        dataLength -= DATA_BLOCK_LENGTH;
652
653        for (int block = 0; block <= dataLength; block += step) {
654            if(equal_int(data, block, otherBlock, DATA_BLOCK_LENGTH)) {
655                return block;
656            }
657        }
658        return -1;
659    }
660
661    /**
662     * Fold the normalization data for supplementary code points into
663     * a compact area on top of the BMP-part of the trie index,
664     * with the lead surrogates indexing this compact area.
665     *
666     * Duplicate the index values for lead surrogates:
667     * From inside the BMP area, where some may be overridden with folded values,
668     * to just after the BMP area, where they can be retrieved for
669     * code point lookups.
670     * @param manipulate fold implementation
671     */
672    private final void fold(DataManipulate manipulate)
673    {
674        int leadIndexes[] = new int[SURROGATE_BLOCK_COUNT_];
675        int index[] = m_index_;
676        // copy the lead surrogate indexes into a temporary array
677        System.arraycopy(index, 0xd800 >> SHIFT_, leadIndexes, 0,
678                         SURROGATE_BLOCK_COUNT_);
679
680        // set all values for lead surrogate code *units* to leadUnitValue
681        // so that by default runtime lookups will find no data for associated
682        // supplementary code points, unless there is data for such code points
683        // which will result in a non-zero folding value below that is set for
684        // the respective lead units
685        // the above saved the indexes for surrogate code *points*
686        // fill the indexes with simplified code from utrie_setRange32()
687        int block = 0;
688        if (m_leadUnitValue_ == m_initialValue_) {
689            // leadUnitValue == initialValue, use all-initial-value block
690            // block = 0; if block here left empty
691        }
692        else {
693            // create and fill the repeatBlock
694            block = allocDataBlock();
695            if (block < 0) {
696                // data table overflow
697                throw new IllegalStateException("Internal error: Out of memory space");
698            }
699            fillBlock(block, 0, DATA_BLOCK_LENGTH, m_leadUnitValue_, true);
700            // negative block number to indicate that it is a repeat block
701            block = -block;
702        }
703        for (int c = (0xd800 >> SHIFT_); c < (0xdc00 >> SHIFT_); ++ c) {
704            m_index_[c] = block;
705        }
706
707        // Fold significant index values into the area just after the BMP
708        // indexes.
709        // In case the first lead surrogate has significant data,
710        // its index block must be used first (in which case the folding is a
711        // no-op).
712        // Later all folded index blocks are moved up one to insert the copied
713        // lead surrogate indexes.
714        int indexLength = BMP_INDEX_LENGTH_;
715        // search for any index (stage 1) entries for supplementary code points
716        for (int c = 0x10000; c < 0x110000;) {
717            if (index[c >> SHIFT_] != 0) {
718                // there is data, treat the full block for a lead surrogate
719                c &= ~0x3ff;
720                // is there an identical index block?
721                block = findSameIndexBlock(index, indexLength, c >> SHIFT_);
722
723                // get a folded value for [c..c+0x400[ and,
724                // if different from the value for the lead surrogate code
725                // point, set it for the lead surrogate code unit
726
727                int value = manipulate.getFoldedValue(c,
728                                                      block + SURROGATE_BLOCK_COUNT_);
729                if (value != getValue(UTF16.getLeadSurrogate(c))) {
730                    if (!setValue(UTF16.getLeadSurrogate(c), value)) {
731                        // data table overflow
732                        throw new ArrayIndexOutOfBoundsException(
733                                                                 "Data table overflow");
734                    }
735                    // if we did not find an identical index block...
736                    if (block == indexLength) {
737                        // move the actual index (stage 1) entries from the
738                        // supplementary position to the new one
739                        System.arraycopy(index, c >> SHIFT_, index, indexLength,
740                                         SURROGATE_BLOCK_COUNT_);
741                        indexLength += SURROGATE_BLOCK_COUNT_;
742                    }
743                }
744                c += 0x400;
745            }
746            else {
747                c += DATA_BLOCK_LENGTH;
748            }
749        }
750
751        // index array overflow?
752        // This is to guarantee that a folding offset is of the form
753        // UTRIE_BMP_INDEX_LENGTH+n*UTRIE_SURROGATE_BLOCK_COUNT with n=0..1023.
754        // If the index is too large, then n>=1024 and more than 10 bits are
755        // necessary.
756        // In fact, it can only ever become n==1024 with completely unfoldable
757        // data and the additional block of duplicated values for lead
758        // surrogates.
759        if (indexLength >= MAX_INDEX_LENGTH_) {
760            throw new ArrayIndexOutOfBoundsException("Index table overflow");
761        }
762        // make space for the lead surrogate index block and insert it between
763        // the BMP indexes and the folded ones
764        System.arraycopy(index, BMP_INDEX_LENGTH_, index,
765                         BMP_INDEX_LENGTH_ + SURROGATE_BLOCK_COUNT_,
766                         indexLength - BMP_INDEX_LENGTH_);
767        System.arraycopy(leadIndexes, 0, index, BMP_INDEX_LENGTH_,
768                         SURROGATE_BLOCK_COUNT_);
769        indexLength += SURROGATE_BLOCK_COUNT_;
770        m_indexLength_ = indexLength;
771    }
772
773    /**
774     * @hide draft / provisional / internal are hidden on Android
775     */
776    private void fillBlock(int block, int start, int limit, int value,
777                           boolean overwrite)
778    {
779        limit += block;
780        block += start;
781        if (overwrite) {
782            while (block < limit) {
783                m_data_[block ++] = value;
784            }
785        }
786        else {
787            while (block < limit) {
788                if (m_data_[block] == m_initialValue_) {
789                    m_data_[block] = value;
790                }
791                ++ block;
792            }
793        }
794    }
795}
796
797