Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* SwitchExpression.java
*
* Copyright (c) 2012 Mike Strobel
*
* This source code is based on the Dynamic Language Runtime from Microsoft,
* Copyright (c) Microsoft Corporation.
*
* This source code is subject to terms and conditions of the Apache License, Version 2.0.
* A copy of the license can be found in the License.html file at the root of this distribution.
* By using this source code in any fashion, you are agreeing to be bound by the terms of the
* Apache License, Version 2.0.
*
* You must not remove this notice, or any other, from this software.
*/
package com.strobel.expressions;
import com.strobel.core.ArrayUtilities;
import com.strobel.core.ReadOnlyList;
import com.strobel.core.VerifyArgument;
import com.strobel.reflection.MethodInfo;
import com.strobel.reflection.PrimitiveTypes;
import com.strobel.reflection.Type;
import com.strobel.reflection.Types;
import com.strobel.reflection.emit.SwitchOptions;
import java.util.ArrayList;
import java.util.HashMap;
/**
* @author strobelm
*/
public final class SwitchExpression extends Expression {
private final Type _type;
private final Expression _switchValue;
private final ReadOnlyList _cases;
private final Expression _defaultBody;
private final MethodInfo _comparison;
private final SwitchOptions _options;
public SwitchExpression(
final Type type,
final Expression switchValue,
final Expression defaultBody,
final MethodInfo comparison,
final ReadOnlyList cases,
final SwitchOptions options) {
_type = VerifyArgument.notNull(type, "type");
_switchValue = VerifyArgument.notNull(switchValue, "switchValue");
_defaultBody = defaultBody;
_comparison = comparison;
_cases = VerifyArgument.notEmpty(cases, "cases");
_options = options != null ? options : SwitchOptions.Default;
}
public final Expression getSwitchValue() {
return _switchValue;
}
public final ReadOnlyList getCases() {
return _cases;
}
public final Expression getDefaultBody() {
return _defaultBody;
}
public final MethodInfo getComparison() {
return _comparison;
}
public final SwitchOptions getOptions() {
return _options;
}
@Override
public final Type> getType() {
return _type;
}
@Override
public final ExpressionType getNodeType() {
return ExpressionType.Switch;
}
@Override
protected final Expression accept(final ExpressionVisitor visitor) {
return visitor.visitSwitch(this);
}
public final SwitchExpression update(
final Expression switchValue,
final ReadOnlyList cases,
final Expression defaultBody,
final SwitchOptions options) {
if (switchValue == _switchValue && options == _options && cases == _cases && defaultBody == _defaultBody) {
return this;
}
return Expression.makeSwitch(_type, switchValue, _options, defaultBody, _comparison, cases);
}
@Override
public boolean canReduce() {
final Type> switchValueType = _switchValue.getType();
return (switchValueType == Types.String && _options != SwitchOptions.PreferTrie ||
switchValueType.isEnum());
}
@Override
public Expression reduce() {
final Type> switchValueType = _switchValue.getType();
if (switchValueType == Types.String && _options != SwitchOptions.PreferTrie) {
return rewriteStringSwitch();
}
if (switchValueType.isEnum()) {
return rewriteEnumSwitch();
}
return this;
}
private Expression rewriteStringSwitch() {
final ArrayList hashList = new ArrayList<>();
final HashMap reverseHashMap = new HashMap<>();
final HashMap caseIndexMap = new HashMap<>();
for (int i = 0, n = _cases.size(); i < n; i++) {
final SwitchCase switchCase = _cases.get(i);
for (final Expression testValue : switchCase.getTestValues()) {
final String value = (String) ((ConstantExpression) testValue).getValue();
final int hash = value.hashCode();
final String[] oldValue = reverseHashMap.put(
hash,
ArrayUtilities.append(reverseHashMap.get(hash), value)
);
if (oldValue == null) {
hashList.add(hash);
}
caseIndexMap.put(value, i);
}
}
final ParameterExpression caseIndex = variable(PrimitiveTypes.Integer);
final ParameterExpression switchValue = variable(_switchValue.getType());
final SwitchCase[] hashCases = new SwitchCase[hashList.size()];
for (int i = 0, n = hashList.size(); i < n; i++) {
final Integer hash = hashList.get(i);
final String[] matchingStrings = reverseHashMap.get(hash);
final Expression[] caseBranches = new Expression[matchingStrings.length];
for (int j = 0; j < matchingStrings.length; j++) {
final String matchingString = matchingStrings[j];
caseBranches[j] = ifThen(
call(switchValue, "equals", constant(matchingString)),
assign(caseIndex, constant(caseIndexMap.get(matchingString)))
);
}
final Expression caseBody;
if (caseBranches.length == 1) {
caseBody = caseBranches[0];
}
else {
caseBody = block(caseBranches);
}
hashCases[i] = switchCase(
block(caseBody),
constant(hash)
);
}
final SwitchExpression hashSwitch = makeSwitch(
call(switchValue, "hashCode"),
_options,
hashCases
);
final SwitchCase[] resultCases = new SwitchCase[_cases.size()];
for (int i = 0, n = _cases.size(); i < n; i++) {
resultCases[i] = switchCase(_cases.get(i).getBody(), constant(i));
}
final SwitchExpression resultSwitch = makeSwitch(
_type,
caseIndex,
SwitchOptions.PreferTable,
_defaultBody,
null,
resultCases
);
return block(
_type,
new ParameterExpression[] { switchValue, caseIndex },
assign(switchValue, _switchValue),
assign(caseIndex, constant(-1)),
hashSwitch,
resultSwitch
);
}
private Expression rewriteEnumSwitch() {
final SwitchCase[] cases = _cases.toArray(new SwitchCase[_cases.size()]);
for (int i = 0, n = _cases.size(); i < n; i++) {
final SwitchCase oldCase = _cases.get(i);
final ExpressionList extends Expression> oldTestValues = oldCase.getTestValues();
final Expression[] testValues = new Expression[oldTestValues.size()];
for (int j = 0, m = oldTestValues.size(); j < m; j++) {
final Enum> enumValue = (Enum>) ((ConstantExpression) oldTestValues.get(j)).getValue();
testValues[j] = constant(enumValue.ordinal());
}
cases[i] = switchCase(oldCase.getBody(), testValues);
}
return makeSwitch(
_type,
call(_switchValue, "ordinal"),
_options,
_defaultBody,
_comparison,
cases
);
}
}