Home | History | Annotate | Download | only in impl
      1 //  2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html#License
      3 /*
      4  *******************************************************************************
      5  * Copyright (C) 1996-2015, International Business Machines Corporation and
      6  * others. All Rights Reserved.
      7  *******************************************************************************
      8  */
      9 package com.ibm.icu.impl;
     10 
     11 import com.ibm.icu.text.Replaceable;
     12 import com.ibm.icu.text.ReplaceableString;
     13 import com.ibm.icu.text.UCharacterIterator;
     14 import com.ibm.icu.text.UTF16;
     15 
     16 /**
     17  * DLF docs must define behavior when Replaceable is mutated underneath
     18  * the iterator.
     19  *
     20  * This and ICUCharacterIterator share some code, maybe they should share
     21  * an implementation, or the common state and implementation should be
     22  * moved up into UCharacterIterator.
     23  *
     24  * What are first, last, and getBeginIndex doing here?!?!?!
     25  */
     26 public class ReplaceableUCharacterIterator extends UCharacterIterator {
     27 
     28     // public constructor ------------------------------------------------------
     29 
     30     /**
     31      * Public constructor
     32      * @param replaceable text which the iterator will be based on
     33      */
     34     public ReplaceableUCharacterIterator(Replaceable replaceable){
     35         if(replaceable==null){
     36             throw new IllegalArgumentException();
     37         }
     38         this.replaceable  = replaceable;
     39         this.currentIndex = 0;
     40     }
     41 
     42     /**
     43      * Public constructor
     44      * @param str text which the iterator will be based on
     45      */
     46     public ReplaceableUCharacterIterator(String str){
     47         if(str==null){
     48             throw new IllegalArgumentException();
     49         }
     50         this.replaceable  = new ReplaceableString(str);
     51         this.currentIndex = 0;
     52     }
     53 
     54     /**
     55      * Public constructor
     56      * @param buf buffer of text on which the iterator will be based
     57      */
     58     public ReplaceableUCharacterIterator(StringBuffer buf){
     59         if(buf==null){
     60             throw new IllegalArgumentException();
     61         }
     62         this.replaceable  = new ReplaceableString(buf);
     63         this.currentIndex = 0;
     64     }
     65 
     66     // public methods ----------------------------------------------------------
     67 
     68     /**
     69      * Creates a copy of this iterator, does not clone the underlying
     70      * <code>Replaceable</code>object
     71      * @return copy of this iterator
     72      */
     73     @Override
     74     public Object clone(){
     75         try {
     76           return super.clone();
     77         } catch (CloneNotSupportedException e) {
     78             return null; // never invoked
     79         }
     80     }
     81 
     82     /**
     83      * Returns the current UTF16 character.
     84      * @return current UTF16 character
     85      */
     86     @Override
     87     public int current(){
     88         if (currentIndex < replaceable.length()) {
     89             return replaceable.charAt(currentIndex);
     90         }
     91         return DONE;
     92     }
     93 
     94     /**
     95      * Returns the current codepoint
     96      * @return current codepoint
     97      */
     98     @Override
     99     public int currentCodePoint(){
    100         // cannot use charAt due to it different
    101         // behaviour when index is pointing at a
    102         // trail surrogate, check for surrogates
    103 
    104         int ch = current();
    105         if(UTF16.isLeadSurrogate((char)ch)){
    106             // advance the index to get the next code point
    107             next();
    108             // due to post increment semantics current() after next()
    109             // actually returns the next char which is what we want
    110             int ch2 = current();
    111             // current should never change the current index so back off
    112             previous();
    113 
    114             if(UTF16.isTrailSurrogate((char)ch2)){
    115                 // we found a surrogate pair
    116                 return Character.toCodePoint((char)ch, (char)ch2);
    117             }
    118         }
    119         return ch;
    120     }
    121 
    122     /**
    123      * Returns the length of the text
    124      * @return length of the text
    125      */
    126     @Override
    127     public int getLength(){
    128         return replaceable.length();
    129     }
    130 
    131     /**
    132      * Gets the current currentIndex in text.
    133      * @return current currentIndex in text.
    134      */
    135     @Override
    136     public int getIndex(){
    137         return currentIndex;
    138     }
    139 
    140     /**
    141      * Returns next UTF16 character and increments the iterator's currentIndex by 1.
    142      * If the resulting currentIndex is greater or equal to the text length, the
    143      * currentIndex is reset to the text length and a value of DONECODEPOINT is
    144      * returned.
    145      * @return next UTF16 character in text or DONE if the new currentIndex is off the
    146      *         end of the text range.
    147      */
    148     @Override
    149     public int next(){
    150         if (currentIndex < replaceable.length()) {
    151             return replaceable.charAt(currentIndex++);
    152         }
    153         return DONE;
    154     }
    155 
    156 
    157     /**
    158      * Returns previous UTF16 character and decrements the iterator's currentIndex by
    159      * 1.
    160      * If the resulting currentIndex is less than 0, the currentIndex is reset to 0 and a
    161      * value of DONECODEPOINT is returned.
    162      * @return next UTF16 character in text or DONE if the new currentIndex is off the
    163      *         start of the text range.
    164      */
    165     @Override
    166     public int previous(){
    167         if (currentIndex > 0) {
    168             return replaceable.charAt(--currentIndex);
    169         }
    170         return DONE;
    171     }
    172 
    173     /**
    174      * <p>Sets the currentIndex to the specified currentIndex in the text and returns that
    175      * single UTF16 character at currentIndex.
    176      * This assumes the text is stored as 16-bit code units.</p>
    177      * @param currentIndex the currentIndex within the text.
    178      * @exception IllegalArgumentException is thrown if an invalid currentIndex is
    179      *            supplied. i.e. currentIndex is out of bounds.
    180      * @returns the character at the specified currentIndex or DONE if the specified
    181      *         currentIndex is equal to the end of the text.
    182      */
    183     @Override
    184     public void setIndex(int currentIndex) throws IndexOutOfBoundsException{
    185         if (currentIndex < 0 || currentIndex > replaceable.length()) {
    186             throw new IndexOutOfBoundsException();
    187         }
    188         this.currentIndex = currentIndex;
    189     }
    190 
    191     @Override
    192     public int getText(char[] fillIn, int offset){
    193         int length = replaceable.length();
    194         if(offset < 0 || offset + length > fillIn.length){
    195             throw new IndexOutOfBoundsException(Integer.toString(length));
    196         }
    197         replaceable.getChars(0,length,fillIn,offset);
    198         return length;
    199     }
    200 
    201     // private data members ----------------------------------------------------
    202 
    203     /**
    204      * Replacable object
    205      */
    206     private Replaceable replaceable;
    207     /**
    208      * Current currentIndex
    209      */
    210     private int currentIndex;
    211 
    212 }
    213