All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.blazebit.collection.PatternTrie Maven / Gradle / Ivy

There is a newer version: 1.6.12
Show newest version
/**
 * Copyright 2012 Blazebit
 * 

* Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at *

* http://www.apache.org/licenses/LICENSE-2.0 *

* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.blazebit.collection; import com.blazebit.regex.Pattern; import com.blazebit.regex.node.*; import java.io.Serializable; import java.util.*; /** * * * @param * The value type that the pattern trie holds. * * @author Christian Beikov * */ public class PatternTrie implements Serializable { private static final long serialVersionUID = 1L; private final TrieNode root; private final Map> patternParameters; private int patternIds = 0; /** * Constructs an empty PatternTrie */ public PatternTrie() { this.root = new TrieNode(); this.patternParameters = new HashMap>(); } public static interface ParameterizedKeyBuilder { ParameterizedKeyBuilder matching(String parameterName, String pattern); ParameterizedKeyBuilder matchingNot(String parameterName, String pattern); void add(); } public static interface ParameterizedValue { public V getValue(); public String getParameter(String patternKey); public Set getParameterNames(); } public PatternTrie add(final CharSequence key, final V value) { if (key == null) { throw new NullPointerException("key"); } /* Avoid casting */ final Map emptyMap = Collections.emptyMap(); add(key.toString().toCharArray(), value, -1, emptyMap); return this; } public ParameterizedKeyBuilder parameterized(final CharSequence pattern, final V value) { if (pattern == null) { throw new NullPointerException("pattern"); } final char[] chars = pattern.toString().toCharArray(); if (chars.length > 0) { /* * We use a linked map so we don't have to take care of parameter * indices */ final Map parameters = new LinkedHashMap(); final ExtendedPattern parameterPattern = new ExtendedPattern(".*", false); int cursor = 0; int parameterStartIndex = -1; while (cursor < chars.length) { switch (chars[cursor]) { case '{': if (parameterStartIndex > -1 && cursor != 0 && chars[cursor - 1] != '\\') { throw new IllegalArgumentException( "Unescaped '{' in parameter name at position " + cursor); } parameterStartIndex = cursor; break; case '}': if (parameterStartIndex < 0 && cursor != 0 && chars[cursor - 1] != '\\') { throw new IllegalArgumentException( "Unescaped '{' found at position " + cursor); } final String parameterName = new String(chars, parameterStartIndex + 1, cursor - parameterStartIndex - 1); if (parameters.put(new Parameter(parameterName, parameterStartIndex), parameterPattern) != null) { throw new IllegalArgumentException("Parameter name '" + parameterName + "' is used twice at position " + parameterStartIndex); } parameterStartIndex = -1; break; default: break; } cursor++; } if (parameterStartIndex > -1) { throw new IllegalArgumentException( "Unclosed bracket at position " + parameterStartIndex); } return new ParameterizedKeyBuilder() { @Override public ParameterizedKeyBuilder matchingNot( String parameterName, String pattern) { if (parameterName == null) { throw new NullPointerException("parameterName"); } /* Position is not relevant for equals-hashCode of Parameter */ if (parameters.put(new Parameter(parameterName, -1), new ExtendedPattern(pattern, true)) == null) { throw new IllegalArgumentException( "Unknown parameter '" + parameterName + "'"); } return this; } @Override public ParameterizedKeyBuilder matching( String parameterName, String pattern) { if (parameterName == null) { throw new NullPointerException("parameterName"); } /* Position is not relevant for equals-hashCode of Parameter */ if (parameters.put(new Parameter(parameterName, -1), new ExtendedPattern(pattern, false)) == null) { throw new IllegalArgumentException( "Unknown parameter '" + parameterName + "'"); } return this; } @Override public void add() { PatternTrie.this .add(chars, value, patternIds++, parameters); } }; } /* Special key build for empty pattern */ return new ParameterizedKeyBuilder() { @Override public ParameterizedKeyBuilder matchingNot(String parameterName, String pattern) { if (parameterName == null) { throw new NullPointerException("parameterName"); } throw new IllegalArgumentException("Unknown parameter '" + parameterName + "'"); } @Override public ParameterizedKeyBuilder matching(String parameterName, String pattern) { if (parameterName == null) { throw new NullPointerException("parameterName"); } throw new IllegalArgumentException("Unknown parameter '" + parameterName + "'"); } @Override public void add() { /* Avoid casting */ final Map emptyMap = Collections .emptyMap(); PatternTrie.this.add(chars, value, -1, emptyMap); } }; } public Set> resolve(String key) { if (key == null) { throw new NullPointerException("key"); } Set> result = new HashSet>(); final char[] chars = key.toString().toCharArray(); Map, Map> currentNodes = new HashMap, Map>( 1); if (root != null) { currentNodes.put(root, new HashMap(0)); } for (int i = 0; i < chars.length && !currentNodes.isEmpty(); i++) { currentNodes = findMatchingNodes(currentNodes, chars[i]); } for (Map.Entry, Map> nodeEntry : currentNodes .entrySet()) { System.out.println(nodeEntry.getKey().value + " ----"); for (ParameterResult parameterResult : nodeEntry.getValue() .values()) { System.out.println(parameterResult.parameter.name + " - " + parameterResult.parameter.patternId + " - " + parameterResult.value.toString()); } } if (!currentNodes.isEmpty()) { for (Map.Entry, Map> nodeEntry : currentNodes .entrySet()) { TrieNode node = nodeEntry.getKey(); if (node.inUse) { for (V nodeValue : node.value) { ParameterizedValueImpl value = new ParameterizedValueImpl( nodeValue); for (ParameterResult parameterResult : nodeEntry .getValue().values()) { if (parameterResult.ended) { value.setParameter( parameterResult.parameter.name, parameterResult.value.toString()); } } result.add(value); } } } } return result; } private static class ParameterResult { private PatternParameter parameter; private StringBuilder value; private boolean ended = false; public ParameterResult(PatternParameter parameter) { this.parameter = parameter; this.value = new StringBuilder(); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((parameter == null) ? 0 : parameter.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof ParameterResult)) { return false; } ParameterResult other = (ParameterResult) obj; if (parameter == null) { if (other.parameter != null) { return false; } } else if (!parameter.equals(other.parameter)) { return false; } return true; } } private Map, Map> findMatchingNodes( Map, Map> nodes, char c) { Map, Map> matchingNodes = new HashMap, Map>( 1); for (Map.Entry, Map> nodeEntry : nodes .entrySet()) { TrieNode node = nodeEntry.getKey(); TrieNode childNode = node.anyCharChild; if (childNode != null) { matchingNodes.put( childNode, getParameterResult(nodeEntry.getValue(), c, childNode.associatedParameters, childNode.associatedParametersEnd)); } childNode = node.children.get(c); if (childNode != null) { matchingNodes.put( childNode, getParameterResult(nodeEntry.getValue(), c, childNode.associatedParameters, childNode.associatedParametersEnd)); } for (Map.Entry> complementNodeEntry : node.complementChildren .entrySet()) { childNode = complementNodeEntry.getValue(); if (complementNodeEntry.getKey() != c || !childNode.associatedParametersEnd.isEmpty()) { matchingNodes.put( childNode, getParameterResult(nodeEntry.getValue(), c, childNode.associatedParameters, childNode.associatedParametersEnd)); } } // Consume the rest of the characters if (node.anyCharChild == null && node.children.isEmpty() && node.complementChildren.isEmpty()) { for (Map.Entry resultEntry : nodeEntry .getValue().entrySet()) { if (node.associatedParametersEnd.contains(resultEntry .getKey())) { matchingNodes.put( node, getParameterResult(nodeEntry.getValue(), c, node.associatedParameters, node.associatedParametersEnd)); } } } } return matchingNodes; } private Map getParameterResult( Map parameterResults, char c, Set associatedParameters, Set associatedParametersEnd) { parameterResults = new HashMap( parameterResults); for (PatternParameter parameter : associatedParameters) { ParameterResult parameterResult = parameterResults.get(parameter); if (parameterResult == null) { parameterResult = new ParameterResult(parameter); parameterResults.put(parameter, parameterResult); } parameterResult.value.append(c); if (associatedParametersEnd.contains(parameter)) { parameterResult.ended = true; } } return parameterResults; } private static final class PatternParameter { private final int patternId; private final int parameterIndex; private final String name; public PatternParameter(int patternId, int parameterIndex, String name) { super(); this.patternId = patternId; this.parameterIndex = parameterIndex; this.name = name; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + parameterIndex; result = prime * result + patternId; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; PatternParameter other = (PatternParameter) obj; if (parameterIndex != other.parameterIndex) return false; if (patternId != other.patternId) return false; return true; } } private static final class Parameter { private final String name; private final int startPosition; public Parameter(String name, int startPosition) { super(); this.name = name; this.startPosition = startPosition; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Parameter other = (Parameter) obj; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } } private static final class ExtendedPattern { private final String pattern; private final boolean negated; public ExtendedPattern(String pattern, boolean negated) { this.pattern = pattern; this.negated = negated; } } private static final class ParameterizedValueImpl implements ParameterizedValue { private V value; private final Map parameters = new HashMap(); public ParameterizedValueImpl(V value) { this.value = value; } @Override public V getValue() { return value; } @Override public String getParameter(String patternKey) { return parameters.get(patternKey); } public Set getParameterNames() { return parameters.keySet(); } public void setParameter(String patternKey, String value) { parameters.put(patternKey, value); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((parameters == null) ? 0 : parameters.hashCode()); result = prime * result + ((value == null) ? 0 : value.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof ParameterizedValueImpl)) { return false; } ParameterizedValueImpl other = (ParameterizedValueImpl) obj; if (parameters == null) { if (other.parameters != null) { return false; } } else if (!parameters.equals(other.parameters)) { return false; } if (value == null) { if (other.value != null) { return false; } } else if (!value.equals(other.value)) { return false; } return true; } } private static final class TrieNode implements Serializable { private static final long serialVersionUID = 1L; private final Map> children = new HashMap>(); private final Map> complementChildren = new HashMap>(); private List value; private boolean inUse; private TrieNode anyCharChild; private final Set associatedParameters = new HashSet(); private final Set associatedParametersEnd = new HashSet(); public TrieNode(final V value) { this.value = new ArrayList(); this.value.add(value); this.inUse = true; } public TrieNode() { this.inUse = false; } @Override public String toString() { return toString(0); } private String toString(int depth) { StringBuilder sb = new StringBuilder(); for (Map.Entry> entry : children.entrySet()) { for (int i = 0; i < depth; i++) { sb.append(' '); } sb.append('[').append(entry.getKey()).append("] = {\n") .append(entry.getValue().toString(depth + 1)); sb.append("\n"); for (int i = 0; i < depth; i++) { sb.append(' '); } sb.append("}"); } return sb.toString(); } } private void add(final char[] pattern, final V value, final int patternId, final Map parameters) { if (pattern.length == 0) { update(root, value); } int cursor = 0; if (parameters.isEmpty()) { TrieNode currentNode = root; TrieNode lastNode = null; /* Simple key */ while (cursor < pattern.length && currentNode != null) { lastNode = currentNode; currentNode = currentNode.children.get(pattern[cursor]); ++cursor; } if (currentNode == null) { cursor--; for (; cursor < pattern.length - 1; cursor++) { final TrieNode nextNode = new TrieNode(); lastNode.children.put(pattern[cursor], nextNode); lastNode = nextNode; } lastNode.children.put(pattern[cursor], new TrieNode(value)); } else { update(currentNode, value); } } else { final List> parameterEntries = new ArrayList>( parameters.entrySet()); List> currentNodes = new ArrayList>(); currentNodes.add(root); patternParameters.put(patternId, new ArrayList()); /* Parameterized key */ int currentParameterIndex = 0; Parameter currentParameter = parameterEntries.get( currentParameterIndex).getKey(); int currentParameterStart = currentParameter.startPosition; for (; cursor < pattern.length - 1; cursor++) { if (currentParameterStart == cursor) { PatternParameter patternParameter = new PatternParameter( patternId, currentParameterIndex, currentParameter.name); patternParameters.get(patternId).add(patternParameter); currentNodes = getOrCreatePatternNodes(currentNodes, patternParameter, parameterEntries.get(currentParameterIndex) .getValue()); cursor = currentParameterStart + currentParameter.name.length(); if (++currentParameterIndex < parameterEntries.size()) { ++cursor; currentParameter = parameterEntries.get( currentParameterIndex).getKey(); currentParameterStart = currentParameter.startPosition; } } else { currentNodes = getOrCreate(currentNodes, pattern[cursor], null); } } if (cursor == pattern.length - 1) { /* Last char in pattern is part of parameter */ update(currentNodes, value); } else { /* Last char in pattern is not part of parameter */ update(getOrCreate(currentNodes, pattern[cursor], null), value); } } } private void update(final TrieNode node, final V value) { if (node.inUse) { node.value.add(value); } else { node.value = new ArrayList(); node.value.add(value); node.inUse = true; } } private void update(final List> nodes, final V value) { for (int i = 0; i < nodes.size(); i++) { update(nodes.get(i), value); } } private List> getOrCreate(List> nodes, Character c, PatternParameter parameter) { List> resultNodes = new ArrayList>(nodes.size()); for (int i = 0; i < nodes.size(); i++) { TrieNode node = nodes.get(i).children.get(c); if (node == null) { node = new TrieNode(); nodes.get(i).children.put(c, node); } resultNodes.add(node); if (parameter != null) { node.associatedParameters.add(parameter); } } return resultNodes; } private List> getOrCreateAnyChar(List> nodes, PatternParameter parameter) { List> resultNodes = new ArrayList>(nodes.size()); for (int i = 0; i < nodes.size(); i++) { TrieNode node = nodes.get(i).anyCharChild; if (node == null) { node = new TrieNode(); nodes.get(i).anyCharChild = node; } resultNodes.add(node); if (parameter != null) { node.associatedParameters.add(parameter); } } return resultNodes; } private List> getOrCreateComplement(List> nodes, Character c, PatternParameter parameter) { List> resultNodes = new ArrayList>(nodes.size()); for (int i = 0; i < nodes.size(); i++) { TrieNode node = nodes.get(i).complementChildren.get(c); if (node == null) { node = new TrieNode(); nodes.get(i).complementChildren.put(c, node); } resultNodes.add(node); if (parameter != null) { node.associatedParameters.add(parameter); } } return resultNodes; } private void mergeIntoNodes(List> nodes, TrieNode node) { if (nodes.isEmpty()) { return; } for (Map.Entry> tempNodeEntry : node.children .entrySet()) { List> newTargetNodes = new ArrayList>(); for (int i = 0; i < nodes.size(); i++) { TrieNode targetNode = nodes.get(i); TrieNode tempTargetNode = targetNode.children .get(tempNodeEntry.getKey()); if (tempTargetNode == null) { targetNode.children.put(tempNodeEntry.getKey(), tempNodeEntry.getValue()); } else { newTargetNodes.add(tempTargetNode); } } mergeIntoNodes(newTargetNodes, tempNodeEntry.getValue()); } for (Map.Entry> tempNodeEntry : node.complementChildren .entrySet()) { List> newTargetNodes = new ArrayList>(); for (int i = 0; i < nodes.size(); i++) { TrieNode targetNode = nodes.get(i); TrieNode tempTargetNode = targetNode.complementChildren .get(tempNodeEntry.getKey()); if (tempTargetNode == null) { targetNode.complementChildren.put(tempNodeEntry.getKey(), tempNodeEntry.getValue()); } else { newTargetNodes.add(tempTargetNode); } } mergeIntoNodes(newTargetNodes, tempNodeEntry.getValue()); } List> newTargetNodes = new ArrayList>(); for (int i = 0; i < nodes.size(); i++) { TrieNode targetNode = nodes.get(i); TrieNode tempTargetNode = targetNode.anyCharChild; if (tempTargetNode == null) { targetNode.anyCharChild = node.anyCharChild; } else { newTargetNodes.add(tempTargetNode); } targetNode.associatedParameters.addAll(node.associatedParameters); targetNode.associatedParametersEnd .addAll(node.associatedParametersEnd); } if (node.anyCharChild != null) { mergeIntoNodes(newTargetNodes, node.anyCharChild); } if (node.inUse) { for (int i = 0; i < nodes.size(); i++) { for (int j = 0; j < node.value.size(); j++) { update(nodes.get(i), node.value.get(j)); } } } } private List> getOrCreatePatternNodes( List> lastNodes, PatternParameter parameter, ExtendedPattern pattern) { /* * Build a deterministic automaton, link the lastNode to the automaton * and return the end state */ TraverseContext context = new TraverseContext(parameter); if (pattern.negated) { context.complement(); } traverse(Pattern.parse(pattern.pattern), context, lastNodes, pattern.negated); List> result = new ArrayList>(context .getEndStates().size()); for (TrieNode endState : context.getEndStates()) { endState.associatedParametersEnd.add(parameter); result.add(endState); } return result; } private static final class TraverseContext { private boolean hasMoreRequired = false; private boolean complement = false; private final Set> endStates = new HashSet>(); private final PatternParameter parameter; public TraverseContext(PatternParameter parameter) { this.parameter = parameter; } public void addEndState(TrieNode state) { endStates.add(state); } public Set> getEndStates() { return endStates; } public boolean isComplement() { return complement; } public void complement() { this.complement = !this.complement; } public boolean hasMoreRequired() { return hasMoreRequired; } public void setHasMoreRequired(boolean hasMoreRequired) { this.hasMoreRequired = hasMoreRequired; } } private boolean moreRequiredExists(Node node, TraverseContext context) { Node nextNode = node.getNext(); while (nextNode != null) { if (!(nextNode instanceof OptionalNode) && (!(nextNode instanceof RepeatNode) || ((RepeatNode) nextNode) .getMin() == 0)) { return true; } nextNode = nextNode.getNext(); } return false; } private List> traverse(Node node, TraverseContext context, List> trieNodes, boolean negated) { List> newNodes = null; boolean moreRequiredSet = false; if (!context.hasMoreRequired()) { moreRequiredSet = moreRequiredExists(node, context); context.setHasMoreRequired(moreRequiredSet); } if (node instanceof OrNode) { OrNode orNode = (OrNode) node; List nodes = orNode.getNodes(); newNodes = new ArrayList>(trieNodes.size() * nodes.size()); for (int i = 0; i < nodes.size(); i++) { newNodes.addAll(traverse(nodes.get(i), context, trieNodes, negated)); } } else if (node instanceof RepeatNode) { RepeatNode repeatNode = (RepeatNode) node; TrieNode tempNode = new TrieNode(); List> tempNodeList = new ArrayList>(1); tempNodeList.add(tempNode); newNodes = traverse(repeatNode.getDecorated(), context, tempNodeList, negated); if (repeatNode.getMax() != Integer.MAX_VALUE) { List> tempNodes = newNodes; newNodes = new ArrayList>(); for (int i = 1; i < repeatNode.getMax(); i++) { tempNodes = traverse(repeatNode.getDecorated(), context, tempNodes, negated); if (i + 1 >= repeatNode.getMin()) { newNodes.addAll(tempNodes); } } } else if (repeatNode.getMin() != 0) { List> tempNodes = newNodes; newNodes = new ArrayList>(); for (int i = 1; i < repeatNode.getMin() - 1; i++) { tempNodes = traverse(repeatNode.getDecorated(), context, tempNodes, negated); } if (repeatNode.getMin() != 1) { TrieNode minFulfilledNode = new TrieNode(); List> minFulfilledNodeList = new ArrayList>( 1); minFulfilledNodeList.add(minFulfilledNode); newNodes = traverse(repeatNode.getDecorated(), context, minFulfilledNodeList, negated); mergeIntoNodes(tempNodes, minFulfilledNode); mergeIntoNodes(newNodes, minFulfilledNode); } else { newNodes = tempNodes; mergeIntoNodes(newNodes, tempNode); } } else { mergeIntoNodes(newNodes, tempNode); } mergeIntoNodes(trieNodes, tempNode); if (repeatNode.getMin() == 0) { newNodes.addAll(trieNodes); } } else if (node instanceof OptionalNode) { newNodes = traverse(((OptionalNode) node).getDecorated(), context, trieNodes, negated); newNodes.addAll(trieNodes); } else if (node instanceof ComplementNode) { context.complement(); newNodes = traverse(((ComplementNode) node).getDecorated(), context, trieNodes, negated); context.complement(); } else if (node instanceof CharRangeNode) { newNodes = new ArrayList>(trieNodes.size()); CharRangeNode rangeNode = (CharRangeNode) node; char start = rangeNode.getStart(); char end = rangeNode.getEnd(); if (context.isComplement()) { for (int i = start; i <= end; i++) { newNodes.addAll(getOrCreateComplement(trieNodes, (char) i, context.parameter)); } } else { for (int i = start; i <= end; i++) { newNodes.addAll(getOrCreate(trieNodes, (char) i, context.parameter)); } } } else if (node instanceof CharNode) { if (context.isComplement()) { newNodes = getOrCreateComplement(trieNodes, ((CharNode) node).getCharacter(), context.parameter); } else { newNodes = getOrCreate(trieNodes, ((CharNode) node).getCharacter(), context.parameter); } } else if (node instanceof DotNode) { newNodes = getOrCreateAnyChar(trieNodes, context.parameter); } else if (node instanceof EmptyNode) { throw new IllegalArgumentException("Empty bracket not allowed"); } else { throw new IllegalArgumentException("Unknown node"); } if (newNodes != null) { if (!context.hasMoreRequired() || negated) { for (int i = 0; i < newNodes.size(); i++) { context.addEndState(newNodes.get(i)); } } if (moreRequiredSet) { context.setHasMoreRequired(false); } if (node.getNext() != null) { newNodes = traverse(node.getNext(), context, newNodes, negated); } } return newNodes; } public String toString() { Map parameterCount = new HashMap(); for (List params : patternParameters.values()) { for (PatternParameter param : params) { parameterCount.put(param, 0); } } return toString(root, new StringBuilder(), 0, parameterCount, 100) .toString(); } private static boolean anyReachedThreshold( Map parameterCount, Set parameters, int charCountThreshold) { for (PatternParameter param : parameters) { if (parameterCount.get(param) == charCountThreshold) { return true; } } return false; } private static StringBuilder toString(TrieNode node, StringBuilder sb, int depth, Map parameterCount, int charCountThreshold) { if (node.inUse) { sb.append(" => "); sb.append(node.value == null ? "null" : node.value.toString()); sb.append('\n'); depth += 2; for (int i = 0; i < depth; i++) { sb.append(' '); } } for (PatternParameter param : node.associatedParameters) { parameterCount.put(param, parameterCount.get(param) + 1); } if (node.children.size() == 1 && node.complementChildren.size() == 0 && node.anyCharChild == null) { Map.Entry> entry = node.children.entrySet() .iterator().next(); sb.append('['); sb.append(entry.getKey()); sb.append(']'); if (anyReachedThreshold(parameterCount, entry.getValue().associatedParameters, charCountThreshold)) { sb.append("(...)"); } else { toString(entry.getValue(), sb, depth, parameterCount, charCountThreshold); } } else if (node.children.size() == 0 && node.complementChildren.size() == 1 && node.anyCharChild == null) { Map.Entry> entry = node.complementChildren .entrySet().iterator().next(); sb.append('[').append('^'); sb.append(entry.getKey()); sb.append(']'); if (anyReachedThreshold(parameterCount, entry.getValue().associatedParameters, charCountThreshold)) { sb.append("(...)"); } else { toString(entry.getValue(), sb, depth, parameterCount, charCountThreshold); } } else if (node.children.size() == 0 && node.complementChildren.size() == 0 && node.anyCharChild != null) { sb.append('.'); if (anyReachedThreshold(parameterCount, node.anyCharChild.associatedParameters, charCountThreshold)) { sb.append("(...)"); } else { toString(node.anyCharChild, sb, depth, parameterCount, charCountThreshold); } } else { depth += 2; for (Map.Entry> entry : node.children .entrySet()) { sb.append('\n'); for (int i = 0; i < depth; i++) { sb.append(' '); } sb.append('['); sb.append(entry.getKey()); sb.append(']'); if (anyReachedThreshold(parameterCount, entry.getValue().associatedParameters, charCountThreshold)) { sb.append("(...)"); } else { toString(entry.getValue(), sb, depth, parameterCount, charCountThreshold); } } for (Map.Entry> entry : node.complementChildren .entrySet()) { sb.append('\n'); for (int i = 0; i < depth; i++) { sb.append(' '); } sb.append('[').append('^'); sb.append(entry.getKey()); sb.append(']'); if (anyReachedThreshold(parameterCount, entry.getValue().associatedParameters, charCountThreshold)) { sb.append("(...)"); } else { toString(entry.getValue(), sb, depth, parameterCount, charCountThreshold); } } if (node.anyCharChild != null) { sb.append('\n'); for (int i = 0; i < depth; i++) { sb.append(' '); } sb.append('.'); if (anyReachedThreshold(parameterCount, node.anyCharChild.associatedParameters, charCountThreshold)) { sb.append("(...)"); } else { toString(node.anyCharChild, sb, depth, parameterCount, charCountThreshold); } } } return sb; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy