Memory performance improvements

This commit is contained in:
serso 2016-01-25 10:34:12 +01:00
parent 9d4365cc79
commit f05d050b6c
14 changed files with 170 additions and 131 deletions

View File

@ -38,7 +38,6 @@ import jscl.NumeralBase;
import jscl.math.numeric.Real;
import jscl.text.DoubleParser;
import jscl.text.JsclIntegerParser;
import jscl.text.MutableInt;
import jscl.text.ParseException;
import jscl.text.Parser;
@ -114,12 +113,16 @@ public class NumberBuilder extends BaseNumberBuilder {
try {
mc.setNumeralBase(nb);
final Parser.Parameters p = Parser.Parameters.get(s);
try {
return JsclIntegerParser.parser.parse(Parser.Parameters.newInstance(s, new MutableInt(0), mc), null).content().doubleValue();
return JsclIntegerParser.parser.parse(p, null).content().doubleValue();
} catch (ParseException e) {
p.exceptionsPool.release(e);
try {
return ((Real) DoubleParser.parser.parse(Parser.Parameters.newInstance(s, new MutableInt(0), mc), null).content()).doubleValue();
p.reset();
return ((Real) DoubleParser.parser.parse(p, null).content()).doubleValue();
} catch (ParseException e1) {
p.exceptionsPool.release(e1);
throw new NumberFormatException();
}
}

View File

@ -24,14 +24,11 @@ package org.solovyev.android.calculator.math.edit;
import android.view.View;
import android.widget.EditText;
import jscl.text.Identifier;
import jscl.text.MutableInt;
import jscl.text.ParseException;
import jscl.text.Parser;
import org.solovyev.android.calculator.VarsRegistry;
import org.solovyev.android.calculator.EntitiesRegistry;
import org.solovyev.android.calculator.Locator;
import org.solovyev.android.calculator.R;
import org.solovyev.android.calculator.VarsRegistry;
import org.solovyev.android.calculator.math.MathType;
import org.solovyev.android.calculator.model.MathEntityBuilder;
import org.solovyev.common.math.MathEntity;
@ -41,6 +38,10 @@ import org.solovyev.common.text.Strings;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import jscl.text.Identifier;
import jscl.text.ParseException;
import jscl.text.Parser;
public class VarEditorSaver<T extends MathEntity> implements View.OnClickListener {
@Nonnull
@ -71,19 +72,16 @@ public class VarEditorSaver<T extends MathEntity> implements View.OnClickListene
}
public static boolean isValidName(@Nullable String name) {
boolean result = false;
if (!Strings.isEmpty(name)) {
try {
if (name == null) throw new AssertionError();
Identifier.parser.parse(Parser.Parameters.newInstance(name, new MutableInt(0), Locator.getInstance().getEngine().getMathEngine()), null);
result = true;
Identifier.parser.parse(Parser.Parameters.get(name), null);
return true;
} catch (ParseException e) {
// not valid name;
}
}
return result;
return false;
}
@Override

View File

@ -1,6 +1,16 @@
package jscl.math;
import jscl.JsclMathEngine;
import org.solovyev.common.Converter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import jscl.math.function.Constant;
import jscl.math.function.Fraction;
import jscl.math.function.Inverse;
@ -8,14 +18,12 @@ import jscl.math.numeric.Real;
import jscl.math.polynomial.Polynomial;
import jscl.math.polynomial.UnivariatePolynomial;
import jscl.mathml.MathML;
import jscl.text.*;
import jscl.text.ExpressionParser;
import jscl.text.ParseException;
import jscl.text.Parser;
import jscl.text.ParserUtils;
import jscl.text.msg.Messages;
import jscl.util.ArrayUtils;
import org.solovyev.common.Converter;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
public class Expression extends Generic {
@ -113,15 +121,13 @@ public class Expression extends Generic {
}
public static Expression valueOf(@Nonnull String expression) throws ParseException {
final MutableInt position = new MutableInt(0);
final Parser.Parameters p = Parser.Parameters.newInstance(expression, position, JsclMathEngine.getInstance());
final Parser.Parameters p = Parser.Parameters.get(expression);
final Generic generic = ExpressionParser.parser.parse(p, null);
ParserUtils.skipWhitespaces(p);
int index = position.intValue();
int index = p.position.intValue();
if (index < expression.length()) {
throw new ParseException(index, expression, Messages.msg_1, index + 1);
}

View File

@ -1,10 +1,10 @@
package jscl.text;
import jscl.math.Generic;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import jscl.math.Generic;
public class CompoundIdentifier implements Parser<String> {
public static final Parser<String> parser = new CompoundIdentifier();
@ -16,12 +16,13 @@ public class CompoundIdentifier implements Parser<String> {
public String parse(@Nonnull Parameters p, @Nullable Generic previousSumElement) throws ParseException {
int pos0 = p.position.intValue();
StringBuilder result = new StringBuilder();
final StringBuilder result;
ParserUtils.skipWhitespaces(p);
try {
String s = Identifier.parser.parse(p, previousSumElement);
result.append(s);
final String identifier = Identifier.parser.parse(p, previousSumElement);
result = new StringBuilder();
result.append(identifier);
} catch (ParseException e) {
p.position.setValue(pos0);
throw e;

View File

@ -1,11 +1,14 @@
package jscl.text;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import jscl.NumeralBase;
import jscl.math.Generic;
import jscl.text.msg.Messages;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static jscl.text.ParserUtils.makeParseException;
import static jscl.text.ParserUtils.skipWhitespaces;
public class Digits implements Parser<String> {
@ -20,15 +23,15 @@ public class Digits implements Parser<String> {
public String parse(@Nonnull Parameters p, @Nullable Generic previousSumElement) throws ParseException {
int pos0 = p.position.intValue();
final StringBuilder result = new StringBuilder();
ParserUtils.skipWhitespaces(p);
skipWhitespaces(p);
final StringBuilder result;
if (p.position.intValue() < p.expression.length() && nb.getAcceptableCharacters().contains(p.expression.charAt(p.position.intValue()))) {
result = new StringBuilder(2);
result.append(p.expression.charAt(p.position.intValue()));
p.position.increment();
} else {
ParserUtils.throwParseException(p, pos0, Messages.msg_9);
throw makeParseException(p, pos0, Messages.msg_9);
}
while (p.position.intValue() < p.expression.length() && nb.getAcceptableCharacters().contains(p.expression.charAt(p.position.intValue()))) {

View File

@ -1,18 +1,19 @@
package jscl.text;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import jscl.NumeralBase;
import jscl.math.Generic;
import jscl.math.NumericWrapper;
import jscl.math.numeric.Real;
import jscl.text.msg.Messages;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class DoubleParser implements Parser<NumericWrapper> {
public static final Parser<NumericWrapper> parser = new DoubleParser();
@ -69,7 +70,6 @@ class FloatingPointLiteral implements Parser<Double> {
final NumeralBase nb = NumeralBaseParser.parser.parse(p, previousSumElement);
final StringBuilder result = new StringBuilder();
boolean digits = false;
boolean point = false;
@ -77,6 +77,7 @@ class FloatingPointLiteral implements Parser<Double> {
final Digits digitsParser = new Digits(nb);
final StringBuilder result = new StringBuilder();
try {
result.append(digitsParser.parse(p, previousSumElement));
digits = true;
@ -167,16 +168,15 @@ class ExponentPart implements Parser<String> {
public String parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException {
int pos0 = p.position.intValue();
final StringBuilder result = new StringBuilder();
ParserUtils.skipWhitespaces(p);
final StringBuilder result;
if (p.position.intValue() < p.expression.length() && (p.expression.charAt(p.position.intValue()) == 'e' || p.expression.charAt(p.position.intValue()) == 'E')) {
char c = p.expression.charAt(p.position.intValue());
result = new StringBuilder();
result.append(p.expression.charAt(p.position.intValue()));
p.position.increment();
result.append(c);
} else {
ParserUtils.throwParseException(p, pos0, Messages.msg_10, 'e', 'E');
throw ParserUtils.makeParseException(p, pos0, Messages.msg_10, 'e', 'E');
}
try {
@ -201,10 +201,10 @@ class SignedInteger implements Parser<String> {
public String parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException {
final int pos0 = p.position.intValue();
final StringBuilder result = new StringBuilder();
ParserUtils.skipWhitespaces(p);
final StringBuilder result = new StringBuilder();
final int pos1 = p.position.intValue();
if (pos1 < p.expression.length() && (p.expression.charAt(pos1) == '+' || MinusParser.isMinus(p.expression.charAt(pos1)))) {
final char c = p.expression.charAt(pos1);

View File

@ -1,14 +1,17 @@
package jscl.text;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class ExceptionsPool {
private static final int MAX_COUNT = 20;
@Nonnull
private final List<ParseException> list = new ArrayList<>();
@ -30,6 +33,9 @@ public class ExceptionsPool {
}
public void release(@Nonnull ParseException e) {
if (list.size() >= MAX_COUNT) {
return;
}
list.add(e);
}
}

View File

@ -1,12 +1,13 @@
package jscl.text;
import jscl.math.Generic;
import jscl.text.msg.Messages;
import java.util.Arrays;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.List;
import jscl.math.Generic;
import jscl.text.msg.Messages;
public class Identifier implements Parser<String> {
@ -30,15 +31,16 @@ public class Identifier implements Parser<String> {
public String parse(@Nonnull Parameters p, @Nullable Generic previousSumElement) throws ParseException {
int pos0 = p.position.intValue();
final StringBuilder result = new StringBuilder();
ParserUtils.skipWhitespaces(p);
final StringBuilder result;
if (p.position.intValue() < p.expression.length() && isValidFirstCharacter(p.expression.charAt(p.position.intValue()))) {
result = new StringBuilder();
result.append(p.expression.charAt(p.position.intValue()));
p.position.increment();
} else {
ParserUtils.throwParseException(p, pos0, Messages.msg_5);
throw ParserUtils.makeParseException(p, pos0, Messages.msg_5);
}
while (p.position.intValue() < p.expression.length() && isValidNotFirstCharacter(p.expression, p.position)) {

View File

@ -1,13 +1,14 @@
package jscl.text;
import java.util.Collections;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import jscl.NumeralBase;
import jscl.math.Generic;
import jscl.text.msg.Messages;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collections;
public class IntegerParser implements Parser<Integer> {
public static final Parser<Integer> parser = new IntegerParser();
@ -18,32 +19,14 @@ public class IntegerParser implements Parser<Integer> {
public Integer parse(@Nonnull Parameters p, @Nullable Generic previousSumElement) throws ParseException {
int pos0 = p.position.intValue();
/*int n;
ParserUtils.skipWhitespaces(expression, position);
if (position.intValue() < expression.length() && Character.isDigit(expression.charAt(position.intValue()))) {
char c = expression.charAt(position.intValue());
position.increment();
n = c - '0';
} else {
position.setValue(pos0);
throw new ParseException();
}
while (position.intValue() < expression.length() && Character.isDigit(expression.charAt(position.intValue()))) {
char c = expression.charAt(position.intValue());
position.increment();
n = 10 * n + (c - '0');
}*/
final NumeralBase nb = NumeralBaseParser.parser.parse(p, previousSumElement);
final StringBuilder result = new StringBuilder();
ParserUtils.skipWhitespaces(p);
final StringBuilder result;
if (p.position.intValue() < p.expression.length() && nb.getAcceptableCharacters().contains(p.expression.charAt(p.position.intValue()))) {
char c = p.expression.charAt(p.position.intValue());
p.position.increment();
result = new StringBuilder();
result.append(c);
} else {
p.position.setValue(pos0);

View File

@ -1,14 +1,15 @@
package jscl.text;
import java.util.Collections;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import jscl.NumeralBase;
import jscl.math.Generic;
import jscl.math.JsclInteger;
import jscl.text.msg.Messages;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collections;
public class JsclIntegerParser implements Parser<JsclInteger> {
public static final Parser<JsclInteger> parser = new JsclIntegerParser();
@ -21,16 +22,14 @@ public class JsclIntegerParser implements Parser<JsclInteger> {
final NumeralBase nb = NumeralBaseParser.parser.parse(p, previousSumElement);
final StringBuilder result = new StringBuilder();
final String number;
try {
result.append(new Digits(nb).parse(p, previousSumElement));
number = new Digits(nb).parse(p, previousSumElement);
} catch (ParseException e) {
p.position.setValue(pos0);
throw e;
}
final String number = result.toString();
try {
return nb.toJsclInteger(number);
} catch (NumberFormatException e) {

View File

@ -1,12 +1,14 @@
package jscl.text;
import jscl.MathContext;
import jscl.math.Generic;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import jscl.JsclMathEngine;
import jscl.MathContext;
import jscl.math.Generic;
/**
* Main parser interface.
@ -28,10 +30,18 @@ public interface Parser<T> {
class Parameters {
@Nonnull
public final String expression;
private static final ThreadLocal<Parameters> instance = new ThreadLocal<Parameters>() {
@Override
protected Parameters initialValue() {
return new Parameters("", JsclMathEngine.getInstance());
}
};
@Nonnull
public final MutableInt position;
public String expression;
@Nonnull
public final MutableInt position = new MutableInt(0);
@Nonnull
public final List<ParseException> exceptions = new ArrayList<ParseException>();
@ -44,18 +54,24 @@ public interface Parser<T> {
/**
* @param expression expression to be parsed
* @param position current position of expression. Side effect: if parsing is successful this parameter should be increased on the number of parsed letters (incl whitespaces etc)
* @param context math engine to be used in parsing
*/
Parameters(@Nonnull String expression, @Nonnull MutableInt position, @Nonnull MathContext context) {
Parameters(@Nonnull String expression, @Nonnull MathContext context) {
this.expression = expression;
this.position = position;
this.context = context;
}
@Nonnull
public static Parameters newInstance(@Nonnull String expression, @Nonnull MutableInt position, @Nonnull final MathContext mathEngine) {
return new Parameters(expression, position, mathEngine);
public static Parameters get(@Nonnull String expression) {
final Parameters parameters = instance.get();
parameters.expression = expression;
parameters.reset();
return parameters;
}
public void reset() {
position.setValue(0);
exceptions.clear();
}
public void addException(@Nonnull ParseException e) {

View File

@ -1,11 +1,13 @@
package jscl.text;
import jscl.math.Generic;
import jscl.text.msg.Messages;
import java.lang.reflect.Array;
import java.util.Collections;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.lang.reflect.Array;
import jscl.math.Generic;
import jscl.text.msg.Messages;
/**
* User: serso
@ -62,14 +64,43 @@ public class ParserUtils {
}
}
public static void throwParseException(@Nonnull Parser.Parameters p,
int pos0,
@Nonnull String messageId) throws ParseException {
throw makeParseException(p, pos0, messageId);
}
@Nonnull
public static ParseException makeParseException(@Nonnull Parser.Parameters p, int pos0, @Nonnull String messageId) {
final MutableInt position = p.position;
final ParseException parseException = p.exceptionsPool.obtain(position.intValue(), p.expression, messageId, Collections.emptyList());
position.setValue(pos0);
return parseException;
}
public static void throwParseException(@Nonnull Parser.Parameters p,
int pos0,
@Nonnull String messageId,
@Nonnull Object parameter) throws ParseException {
final MutableInt position = p.position;
final ParseException parseException = p.exceptionsPool.obtain(position.intValue(), p.expression, messageId, Collections.singletonList(parameter));
position.setValue(pos0);
throw parseException;
}
public static void throwParseException(@Nonnull Parser.Parameters p,
int pos0,
@Nonnull String messageId,
Object... parameters) throws ParseException {
throw makeParseException(p, pos0, messageId, parameters);
}
@Nonnull
public static ParseException makeParseException(@Nonnull Parser.Parameters p, int pos0, @Nonnull String messageId, Object... parameters) {
final MutableInt position = p.position;
final ParseException parseException = p.exceptionsPool.obtain(position.intValue(), p.expression, messageId, parameters);
position.setValue(pos0);
throw parseException;
return parseException;
}

View File

@ -1,17 +1,17 @@
package jscl.text;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import jscl.math.Generic;
import jscl.math.function.PostfixFunctionsRegistry;
import jscl.math.operator.Operator;
import jscl.math.operator.TripleFactorial;
import jscl.text.msg.Messages;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* User: serso
* Date: 10/31/11
@ -26,13 +26,14 @@ public class PostfixFunctionsParser implements Parser<Generic> {
this.content = content;
}
private static Generic parsePostfix(@Nonnull List<PostfixFunctionParser> parsers,
private static Generic parsePostfix(@Nonnull List<String> names,
Generic content,
@Nullable final Generic previousSumElement,
@Nonnull final Parameters p) throws ParseException {
Generic result = content;
for (PostfixFunctionParser parser : parsers) {
for (String name : names) {
final PostfixFunctionParser parser = new PostfixFunctionParser(name);
final PostfixFunctionParser.Result postfixResult = parser.parse(p, previousSumElement);
if (postfixResult.isPostfixFunction()) {
final Operator postfixFunction;
@ -51,7 +52,7 @@ public class PostfixFunctionsParser implements Parser<Generic> {
}
}
result = parsePostfix(parsers, postfixFunction.expressionValue(), previousSumElement, p);
result = parsePostfix(names, postfixFunction.expressionValue(), previousSumElement, p);
}
}
@ -59,15 +60,6 @@ public class PostfixFunctionsParser implements Parser<Generic> {
}
public Generic parse(@Nonnull Parameters p, Generic previousSumElement) throws ParseException {
final List<String> postfixFunctionNames = PostfixFunctionsRegistry.getInstance().getNames();
final List<PostfixFunctionParser> parsers = new ArrayList<PostfixFunctionParser>(postfixFunctionNames.size());
parsers.add(new PostfixFunctionParser(TripleFactorial.NAME));
for (String postfixFunctionName : postfixFunctionNames) {
parsers.add(new PostfixFunctionParser(postfixFunctionName));
}
return parsePostfix(parsers, content, previousSumElement, p);
return parsePostfix(PostfixFunctionsRegistry.getInstance().getNames(), content, previousSumElement, p);
}
}

View File

@ -1,6 +1,5 @@
package jscl.text;
import jscl.JsclMathEngine;
import org.junit.Assert;
/**
@ -12,13 +11,13 @@ public class PowerParserTest {
@org.junit.Test
public void testParse() throws Exception {
PowerParser.parser.parse(Parser.Parameters.newInstance(" ^", new MutableInt(0), JsclMathEngine.getInstance()), null);
PowerParser.parser.parse(Parser.Parameters.newInstance(" **", new MutableInt(0), JsclMathEngine.getInstance()), null);
PowerParser.parser.parse(Parser.Parameters.newInstance(" **7", new MutableInt(0), JsclMathEngine.getInstance()), null);
PowerParser.parser.parse(Parser.Parameters.newInstance("^", new MutableInt(0), JsclMathEngine.getInstance()), null);
PowerParser.parser.parse(Parser.Parameters.newInstance("**", new MutableInt(0), JsclMathEngine.getInstance()), null);
PowerParser.parser.parse(Parser.Parameters.get(" ^"), null);
PowerParser.parser.parse(Parser.Parameters.get(" **"), null);
PowerParser.parser.parse(Parser.Parameters.get(" **7"), null);
PowerParser.parser.parse(Parser.Parameters.get("^"), null);
PowerParser.parser.parse(Parser.Parameters.get("**"), null);
try {
PowerParser.parser.parse(Parser.Parameters.newInstance("*", new MutableInt(0), JsclMathEngine.getInstance()), null);
PowerParser.parser.parse(Parser.Parameters.get("*"), null);
Assert.fail();
} catch (ParseException e) {