ReplaceableContextIterator.java
// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
*******************************************************************************
*
* Copyright (C) 2004-2010, International Business Machines
* Corporation and others. All Rights Reserved.
*
*******************************************************************************
* file name: ReplaceableContextIterator.java
* encoding: US-ASCII
* tab size: 8 (not used)
* indentation:4
*
* created on: 2005feb04
* created by: Markus W. Scherer
*
* Implementation of UCaseProps.ContextIterator, iterates over a Replaceable.
* Java port of casetrn.cpp/utrans_rep_caseContextIterator().
*/
package com.ibm.icu.text;
import com.ibm.icu.impl.UCaseProps;
/**
* Implementation of UCaseProps.ContextIterator, iterates over a Replaceable. See
* casetrn.cpp/utrans_rep_caseContextIterator(). See also UCharacter.StringContextIterator.
*/
class ReplaceableContextIterator implements UCaseProps.ContextIterator {
/**
* Constructor.
*
* @param rep Replaceable to iterate over.
*/
ReplaceableContextIterator() {
this.rep = null;
limit = cpStart = cpLimit = index = contextStart = contextLimit = 0;
dir = 0;
reachedLimit = false;
}
/**
* Set the text for iteration.
*
* @param rep Iteration text.
*/
public void setText(Replaceable rep) {
this.rep = rep;
limit = contextLimit = rep.length();
cpStart = cpLimit = index = contextStart = 0;
dir = 0;
reachedLimit = false;
}
/**
* Set the index where nextCaseMapCP() is to start iterating.
*
* @param index Iteration start index for nextCaseMapCP().
*/
public void setIndex(int index) {
cpStart = cpLimit = index;
this.index = 0;
dir = 0;
reachedLimit = false;
}
/**
* Get the index of where the code point currently being case-mapped starts.
*
* @return The start index of the current code point.
*/
public int getCaseMapCPStart() {
return cpStart;
}
/**
* Set the iteration limit for nextCaseMapCP() to an index within the string. If the limit
* parameter is negative or past the string, then the string length is restored as the iteration
* limit.
*
* @param lim The iteration limit.
*/
public void setLimit(int lim) {
if (0 <= lim && lim <= rep.length()) {
limit = lim;
} else {
limit = rep.length();
}
reachedLimit = false;
}
/**
* Set the start and limit indexes for context iteration with next().
*
* @param contextStart Start of context for next().
* @param contextLimit Limit of context for next().
*/
public void setContextLimits(int contextStart, int contextLimit) {
if (contextStart < 0) {
this.contextStart = 0;
} else if (contextStart <= rep.length()) {
this.contextStart = contextStart;
} else {
this.contextStart = rep.length();
}
if (contextLimit < this.contextStart) {
this.contextLimit = this.contextStart;
} else if (contextLimit <= rep.length()) {
this.contextLimit = contextLimit;
} else {
this.contextLimit = rep.length();
}
reachedLimit = false;
}
/**
* Iterate forward through the string to fetch the next code point to be case-mapped, and set
* the context indexes for it.
*
* @return The next code point to be case-mapped, or <0 when the iteration is done.
*/
public int nextCaseMapCP() {
int c;
if (cpLimit < limit) {
cpStart = cpLimit;
c = rep.char32At(cpLimit);
cpLimit += UTF16.getCharCount(c);
return c;
} else {
return -1;
}
}
/**
* Replace the current code point by its case mapping, and update the indexes.
*
* @param text Replacement text.
* @return The delta for the change of the text length.
*/
public int replace(String text) {
int delta = text.length() - (cpLimit - cpStart);
rep.replace(cpStart, cpLimit, text);
cpLimit += delta;
limit += delta;
contextLimit += delta;
return delta;
}
/**
* Did forward context iteration with next() reach the iteration limit?
*
* @return Boolean value.
*/
public boolean didReachLimit() {
return reachedLimit;
}
// implement UCaseProps.ContextIterator
@Override
public void reset(int direction) {
if (direction > 0) {
/* reset for forward iteration */
this.dir = 1;
index = cpLimit;
} else if (direction < 0) {
/* reset for backward iteration */
this.dir = -1;
index = cpStart;
} else {
// not a valid direction
this.dir = 0;
index = 0;
}
reachedLimit = false;
}
@Override
public int next() {
int c;
if (dir > 0) {
if (index < contextLimit) {
c = rep.char32At(index);
index += UTF16.getCharCount(c);
return c;
} else {
// forward context iteration reached the limit
reachedLimit = true;
}
} else if (dir < 0 && index > contextStart) {
c = rep.char32At(index - 1);
index -= UTF16.getCharCount(c);
return c;
}
return -1;
}
// variables
protected Replaceable rep;
protected int index, limit, cpStart, cpLimit, contextStart, contextLimit;
protected int dir; // 0=initial state >0=forward <0=backward
protected boolean reachedLimit;
}