/* GENERATED SOURCE. DO NOT MODIFY. */ // © 2016 and later: Unicode, Inc. and others. // License & terms of use: http://www.unicode.org/copyright.html /* ******************************************************************************* * Copyright (C) 2011-2014, International Business Machines * Corporation and others. All Rights Reserved. ******************************************************************************* * created on: 2011jan05 * created by: Markus W. Scherer * ported from ICU4C stringtriebuilder.h/.cpp */ package android.icu.util; import java.util.ArrayList; import java.util.HashMap; /** * Base class for string trie builder classes. * *
This class is not intended for public subclassing. * * @author Markus W. Scherer * @hide Only a subset of ICU is exposed in Android */ public abstract class StringTrieBuilder { /** * Build options for BytesTrieBuilder and CharsTrieBuilder. * @hide Only a subset of ICU is exposed in Android */ public enum Option { /** * Builds a trie quickly. */ FAST, /** * Builds a trie more slowly, attempting to generate * a shorter but equivalent serialization. * This build option also uses more memory. * *
This option can be effective when many integer values are the same
* and string/byte sequence suffixes can be shared.
* Runtime speed is not expected to improve.
*/
SMALL
}
/**
* @deprecated This API is ICU internal only.
* @hide draft / provisional / internal are hidden on Android
*/
@Deprecated
protected StringTrieBuilder() {}
/**
* @deprecated This API is ICU internal only.
* @hide draft / provisional / internal are hidden on Android
*/
@Deprecated
protected void addImpl(CharSequence s, int value) {
if(state!=State.ADDING) {
// Cannot add elements after building.
throw new IllegalStateException("Cannot add (string, value) pairs after build().");
}
if(s.length()>0xffff) {
// Too long: Limited by iterator internals, and by builder recursion depth.
throw new IndexOutOfBoundsException("The maximum string length is 0xffff.");
}
if(root==null) {
root=createSuffixNode(s, 0, value);
} else {
root=root.add(this, s, 0, value);
}
}
/**
* @deprecated This API is ICU internal only.
* @hide draft / provisional / internal are hidden on Android
*/
@Deprecated
protected final void buildImpl(Option buildOption) {
switch(state) {
case ADDING:
if(root==null) {
throw new IndexOutOfBoundsException("No (string, value) pairs were added.");
}
if(buildOption==Option.FAST) {
state=State.BUILDING_FAST;
// Building "fast" is somewhat faster (25..50% in some test)
// because it makes registerNode() return the input node
// rather than checking for duplicates.
// As a result, we sometimes write larger trie serializations.
//
// In either case we need to fix-up linear-match nodes (for their maximum length)
// and branch nodes (turning dynamic branch nodes into trees of
// runtime-equivalent nodes), but the HashMap/hashCode()/equals() are omitted for
// nodes other than final values.
} else {
state=State.BUILDING_SMALL;
}
break;
case BUILDING_FAST:
case BUILDING_SMALL:
// Building must have failed.
throw new IllegalStateException("Builder failed and must be clear()ed.");
case BUILT:
return; // Nothing more to do.
}
// Implementation note:
// We really build three versions of the trie.
// The first is a fully dynamic trie, built successively by addImpl().
// Then we call root.register() to turn it into a tree of nodes
// which is 1:1 equivalent to the runtime data structure.
// Finally, root.markRightEdgesFirst() and root.write() write that serialized form.
root=root.register(this);
root.markRightEdgesFirst(-1);
root.write(this);
state=State.BUILT;
}
/**
* @deprecated This API is ICU internal only.
* @hide draft / provisional / internal are hidden on Android
*/
@Deprecated
protected void clearImpl() {
strings.setLength(0);
nodes.clear();
root=null;
state=State.ADDING;
}
/**
* Makes sure that there is only one unique node registered that is
* equivalent to newNode, unless BUILDING_FAST.
* @param newNode Input node. The builder takes ownership.
* @return newNode if it is the first of its kind, or
* an equivalent node if newNode is a duplicate.
*/
private final Node registerNode(Node newNode) {
if(state==State.BUILDING_FAST) {
return newNode;
}
// BUILDING_SMALL
Node oldNode=nodes.get(newNode);
if(oldNode!=null) {
return oldNode;
}
// If put() returns a non-null value from an equivalent, previously
// registered node, then get() failed to find that and we will leak newNode.
oldNode=nodes.put(newNode, newNode);
assert(oldNode==null);
return newNode;
}
/**
* Makes sure that there is only one unique FinalValueNode registered
* with this value.
* Avoids creating a node if the value is a duplicate.
* @param value A final value.
* @return A FinalValueNode with the given value.
*/
private final ValueNode registerFinalValue(int value) {
// We always register final values because while ADDING
// we do not know yet whether we will build fast or small.
lookupFinalValueNode.setFinalValue(value);
Node oldNode=nodes.get(lookupFinalValueNode);
if(oldNode!=null) {
return (ValueNode)oldNode;
}
ValueNode newNode=new ValueNode(value);
// If put() returns a non-null value from an equivalent, previously
// registered node, then get() failed to find that and we will leak newNode.
oldNode=nodes.put(newNode, newNode);
assert(oldNode==null);
return newNode;
}
private static abstract class Node {
public Node() {
offset=0;
}
// hashCode() and equals() for use with registerNode() and the nodes hash.
@Override
public abstract int hashCode() /*const*/;
// Base class equals() compares the actual class types.
@Override
public boolean equals(Object other) {
return this==other || this.getClass()==other.getClass();
}
/**
* Recursive method for adding a new (string, value) pair.
* Matches the remaining part of s from start,
* and adds a new node where there is a mismatch.
* @return this or a replacement Node
*/
public Node add(StringTrieBuilder builder, CharSequence s, int start, int sValue) {
return this;
}
/**
* Recursive method for registering unique nodes,
* after all (string, value) pairs have been added.
* Final-value nodes are pre-registered while add()ing (string, value) pairs.
* Other nodes created while add()ing registerNode() themselves later
* and might replace themselves with new types of nodes for write()ing.
* @return The registered version of this node which implements write().
*/
public Node register(StringTrieBuilder builder) { return this; }
/**
* Traverses the Node graph and numbers branch edges, with rightmost edges first.
* This is to avoid writing a duplicate node twice.
*
* Branch nodes in this trie data structure are not symmetric.
* Most branch edges "jump" to other nodes but the rightmost branch edges
* just continue without a jump.
* Therefore, write() must write the rightmost branch edge last
* (trie units are written backwards), and must write it at that point even if
* it is a duplicate of a node previously written elsewhere.
*
* This function visits and marks right branch edges first.
* Edges are numbered with increasingly negative values because we share the
* offset field which gets positive values when nodes are written.
* A branch edge also remembers the first number for any of its edges.
*
* When a further-left branch edge has a number in the range of the rightmost
* edge's numbers, then it will be written as part of the required right edge
* and we can avoid writing it first.
*
* After root.markRightEdgesFirst(-1) the offsets of all nodes are negative
* edge numbers.
*
* @param edgeNumber The first edge number for this node and its sub-nodes.
* @return An edge number that is at least the maximum-negative
* of the input edge number and the numbers of this node and all of its sub-nodes.
*/
public int markRightEdgesFirst(int edgeNumber) {
if(offset==0) {
offset=edgeNumber;
}
return edgeNumber;
}
// write() must set the offset to a positive value.
public abstract void write(StringTrieBuilder builder);
// See markRightEdgesFirst.
public final void writeUnlessInsideRightEdge(int firstRight, int lastRight,
StringTrieBuilder builder) {
// Note: Edge numbers are negative, lastRight<=firstRight.
// If offset>0 then this node and its sub-nodes have been written already
// and we need not write them again.
// If this node is part of the unwritten right branch edge,
// then we wait until that is written.
if(offset<0 && (offset