functions registry added + vars registry refactored

This commit is contained in:
serso 2011-10-29 14:25:15 +04:00
parent 7d6f2f13e7
commit 89c2ea3a9c
13 changed files with 97 additions and 214 deletions

View File

@ -18,9 +18,9 @@ import android.widget.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.math.MathType;
import org.solovyev.android.calculator.model.AndroidVarsRegistry;
import org.solovyev.android.calculator.model.CalculatorEngine;
import org.solovyev.android.calculator.model.Var;
import org.solovyev.android.calculator.model.VarsRegister;
import org.solovyev.common.utils.StringUtils;
import java.util.ArrayList;
@ -45,7 +45,7 @@ public class CalculatorVarsActivity extends ListActivity {
setContentView(R.layout.vars);
adapter = new VarsArrayAdapter(this, R.layout.var, R.id.var_text, new ArrayList<Var>(CalculatorEngine.instance.getVarsRegister().getVars()));
adapter = new VarsArrayAdapter(this, R.layout.var, R.id.var_text, new ArrayList<Var>(CalculatorEngine.instance.getVarsRegister().getEntities()));
setListAdapter(adapter);
final ListView lv = getListView();
@ -193,9 +193,9 @@ public class CalculatorVarsActivity extends ListActivity {
String description = editDescription.getText().toString();
final VarsRegister varsRegister = CalculatorEngine.instance.getVarsRegister();
final AndroidVarsRegistry varsRegistry = CalculatorEngine.instance.getVarsRegister();
if (!StringUtils.isEmpty(name)) {
final Var varFromRegister = varsRegister.getVar(name);
final Var varFromRegister = varsRegistry.get(name);
if (varFromRegister == null || varFromRegister == editedInstance) {
final MathType.Result mathType = MathType.getType(name, 0);
@ -240,12 +240,12 @@ public class CalculatorVarsActivity extends ListActivity {
createEditVariableDialog(editedInstance, name, value, description);
} else {
if ( editedInstance == null ) {
CalculatorVarsActivity.this.adapter.add(varsRegister.addVar(null, varBuilder));
CalculatorVarsActivity.this.adapter.add(varsRegistry.add(null, varBuilder));
} else {
varsRegister.addVar(editedInstance.getName(), varBuilder);
varsRegistry.add(editedInstance.getName(), varBuilder);
}
varsRegister.save(CalculatorVarsActivity.this);
varsRegistry.save(CalculatorVarsActivity.this);
CalculatorVarsActivity.this.adapter.notifyDataSetChanged();
}
@ -346,9 +346,9 @@ public class CalculatorVarsActivity extends ListActivity {
builder.create().show();
} else {
adapter.remove(var);
final VarsRegister varsRegister = CalculatorEngine.instance.getVarsRegister();
varsRegister.remove(var);
varsRegister.save(CalculatorVarsActivity.this);
final AndroidVarsRegistry varsRegistry = CalculatorEngine.instance.getVarsRegister();
varsRegistry.remove(var);
varsRegistry.save(CalculatorVarsActivity.this);
CalculatorVarsActivity.this.adapter.notifyDataSetChanged();
}
}

View File

@ -19,35 +19,6 @@ public class Functions {
throw new AssertionError("Not allowed!");
}
public final static String SIN = "sin";
public final static String SINH = "sinh";
public final static String ASIN = "asin";
public final static String ASINH = "asinh";
public final static String COS = "cos";
public final static String COSH = "cosh";
public final static String ACOS = "acos";
public final static String ACOSH = "acosh";
public final static String TAN = "tan";
public final static String TANH = "tanh";
public final static String ATAN = "atan";
public final static String ATANH = "atanh";
public final static String LN = "ln";
public final static String LG = "lg";
public final static String MOD = "mod";
public final static String EXP = "exp";
public final static String SQRT = "";
public static final List<String> allPrefix;
static {
final List<String> functions = new ArrayList<String>(Arrays.asList(SIN, SINH, ASIN, ASINH, COS, COSH, ACOS, ACOSH, TAN, TANH, ATAN, ATANH, LN, LG, MOD, SQRT, EXP));
Collections.sort(functions, new MathEntityComparator());
allPrefix = functions;
}
public final static String DEGREE = "°";
public static final List<String> allPostfix = Arrays.asList(DEGREE);

View File

@ -1,22 +0,0 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.calculator.math;
import java.util.Comparator;
/**
* User: serso
* Date: 10/3/11
* Time: 12:30 AM
*/
public class MathEntityComparator implements Comparator<String> {
@Override
public int compare(String s, String s1) {
return s1.length() - s.length();
}
}

View File

@ -7,7 +7,6 @@ package org.solovyev.android.calculator.math;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.CharacterAtPositionFinder;
import org.solovyev.android.calculator.StartsWithFinder;
import org.solovyev.android.calculator.model.CalculatorEngine;
import org.solovyev.android.calculator.model.ParseException;
@ -19,7 +18,6 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import static org.solovyev.common.utils.CollectionsUtils.get;
public enum MathType {
@ -129,13 +127,19 @@ public enum MathType {
}
},
function(1000, true, true, Functions.allPrefix),
function(1000, true, true) {
@NotNull
@Override
public List<String> getTokens() {
return CalculatorEngine.instance.getFunctionsRegistry().getNames();
}
},
constant(1100, true, true) {
@NotNull
@Override
public List<String> getTokens() {
return CalculatorEngine.instance.getVarsRegister().getVarNames();
return CalculatorEngine.instance.getVarsRegister().getNames();
}
},
@ -324,7 +328,7 @@ public enum MathType {
final StartsWithFinder startsWithFinder = new StartsWithFinder(text, i);
for (MathType mathType : getMathTypesByPriority()) {
final String s = get(mathType.getTokens(), startsWithFinder);
final String s = CollectionsUtils.find(mathType.getTokens(), startsWithFinder);
if (s != null) {
return new Result(mathType, s);
}
@ -387,14 +391,6 @@ public enum MathType {
}
}
private static boolean contains(@NotNull List<String> list, @NotNull final Finder<String> startsWithFinder) {
return get(list, startsWithFinder) != null;
}
private static boolean contains(@NotNull List<Character> list, @NotNull final CharacterAtPositionFinder atPositionFinder) {
return get(list, atPositionFinder) != null;
}
private static class EndsWithFinder implements Finder<String> {
private int i;

View File

@ -7,35 +7,19 @@
package org.solovyev.android.calculator.model;
import android.content.Context;
import android.content.SharedPreferences;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import org.solovyev.common.math.MathRegistry;
/**
* User: serso
* Date: 10/6/11
* Time: 9:31 PM
*/
public interface VarsRegister {
public interface AndroidVarsRegistry extends MathRegistry<Var>{
@NotNull
List<Var> getVars();
@NotNull
List<Var> getSystemVars();
Var addVar(@Nullable String name, @NotNull Var.Builder builder);
void remove(@NotNull Var var);
@NotNull
List<String> getVarNames();
@Nullable
Var getVar(@NotNull String name);
boolean contains(@NotNull String name);
void init(@Nullable Context context, @Nullable SharedPreferences preferences);
void save(@NotNull Context context);
}

View File

@ -14,114 +14,38 @@ import org.jetbrains.annotations.Nullable;
import org.simpleframework.xml.Serializer;
import org.simpleframework.xml.core.Persister;
import org.solovyev.android.calculator.R;
import org.solovyev.android.calculator.math.MathEntityComparator;
import org.solovyev.android.calculator.math.MathType;
import org.solovyev.common.utils.CollectionsUtils;
import org.solovyev.common.utils.Finder;
import org.solovyev.common.math.AbstractMathRegistry;
import java.io.StringWriter;
import java.util.*;
/**
* User: serso
* Date: 9/29/11
* Time: 4:57 PM
*/
class VarsRegisterImpl implements VarsRegister {
class AndroidVarsRegistryImpl extends AbstractMathRegistry<Var> implements AndroidVarsRegistry {
@NotNull
private final List<Var> vars = new ArrayList<Var>();
@NotNull
private final List<Var> systemVars = new ArrayList<Var>();
protected VarsRegisterImpl() {
protected AndroidVarsRegistryImpl() {
}
@Override
@NotNull
public List<Var> getVars() {
return Collections.unmodifiableList(vars);
}
@Override
@NotNull
public List<Var> getSystemVars() {
return Collections.unmodifiableList(systemVars);
}
@Override
public Var addVar(@Nullable String name, @NotNull Var.Builder builder) {
final Var var = builder.create();
Var varFromRegister = getVar(name == null ? var.getName() : name);
if (varFromRegister == null) {
varFromRegister = var;
vars.add(var);
} else {
varFromRegister.copy(var);
}
return varFromRegister;
}
@Override
public void remove(@NotNull Var var) {
this.vars.remove(var);
}
@Override
@NotNull
public List<String> getVarNames() {
final List<String> result = new ArrayList<String>();
for (Var var : vars) {
result.add(var.getName());
}
Collections.sort(result, new MathEntityComparator());
return result;
}
@Override
@Nullable
public Var getVar(@NotNull final String name) {
return CollectionsUtils.get(vars, new Finder<Var>() {
@Override
public boolean isFound(@Nullable Var var) {
return var != null && name.equals(var.getName());
}
});
}
@Override
public boolean contains(@NotNull final String name) {
return CollectionsUtils.get(vars, new Finder<Var>() {
@Override
public boolean isFound(@Nullable Var var) {
return var != null && name.equals(var.getName());
}
}) != null;
}
public void merge(@NotNull final List<Var> varsParam) {
/* public void merge(@NotNull final List<Var> varsParam) {
final Set<Var> result = new HashSet<Var>(varsParam);
for (Var systemVar : systemVars) {
for (Var systemVar : systemEntities) {
if (!result.contains(systemVar)) {
result.add(systemVar);
}
}
vars.clear();
vars.addAll(result);
}
entities.clear();
entities.addAll(result);
}*/
synchronized void init(@Nullable Context context, @Nullable SharedPreferences preferences) {
public synchronized void init(@Nullable Context context, @Nullable SharedPreferences preferences) {
this.vars.clear();
this.systemVars.clear();
this.entities.clear();
this.systemEntities.clear();
if (context != null && preferences != null) {
final String value = preferences.getString(context.getString(R.string.p_calc_vars), null);
@ -129,7 +53,7 @@ class VarsRegisterImpl implements VarsRegister {
final Serializer serializer = new Persister();
try {
final Vars vars = serializer.read(Vars.class, value);
this.vars.addAll(vars.getVars());
this.entities.addAll(vars.getVars());
} catch (Exception e) {
throw new RuntimeException(e);
}
@ -181,15 +105,15 @@ class VarsRegisterImpl implements VarsRegister {
final Var systemVar = builder.create();
systemVars.add(systemVar);
if (!vars.contains(systemVar)) {
vars.add(systemVar);
systemEntities.add(systemVar);
if (!entities.contains(systemVar)) {
entities.add(systemVar);
}
}
/*Log.d(VarsRegister.class.getName(), vars.size() + " variables registered!");
/*Log.d(AndroidVarsRegistry.class.getName(), vars.size() + " variables registered!");
for (Var var : vars) {
Log.d(VarsRegister.class.getName(), var.toString());
Log.d(AndroidVarsRegistry.class.getName(), var.toString());
}*/
}
@ -199,7 +123,7 @@ class VarsRegisterImpl implements VarsRegister {
final SharedPreferences.Editor editor = settings.edit();
final Vars vars = new Vars();
for (Var var : this.vars) {
for (Var var : this.entities) {
if (!var.isSystem()) {
vars.getVars().add(var);
}

View File

@ -8,6 +8,8 @@ package org.solovyev.android.calculator.model;
import android.content.Context;
import android.content.SharedPreferences;
import jscl.math.Expression;
import jscl.math.function.Function;
import jscl.math.function.FunctionsRegistry;
import jscl.text.ParseInterruptedException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -15,6 +17,7 @@ import org.solovyev.android.calculator.R;
import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.android.msg.AndroidMessage;
import org.solovyev.common.NumberMapper;
import org.solovyev.common.math.MathRegistry;
import org.solovyev.common.msg.MessageRegistry;
import org.solovyev.common.msg.MessageType;
import org.solovyev.common.utils.CollectionsUtils;
@ -61,7 +64,10 @@ public enum CalculatorEngine {
public final TextProcessor<PreparedExpression> preprocessor = new ToJsclTextProcessor();
@NotNull
private final VarsRegisterImpl varsRegister = new VarsRegisterImpl();
private final AndroidVarsRegistry varsRegister = new AndroidVarsRegistryImpl();
@NotNull
private final MathRegistry<Function> functionsRegistry = FunctionsRegistry.getInstance();
@NotNull
private final static Set<String> tooLongExecutionCache = new HashSet<String>();
@ -180,9 +186,9 @@ public enum CalculatorEngine {
calculationThread.setObject(thread);
calculationResult.setObject(finalOperation.evaluate(Expression.valueOf(jsclExpression)));
} catch (ArithmeticException e) {
exception.setObject(new ParseException(e));
exception.setObject(new ParseException(e.getMessage(), e));
} catch (jscl.text.ParseException e) {
exception.setObject(new ParseException(e));
exception.setObject(new ParseException(e.getMessage(), e));
} catch (ParseInterruptedException e) {
System.out.print("Interrupted!");
// do nothing - we ourselves interrupt the calculations
@ -282,10 +288,15 @@ public enum CalculatorEngine {
}
@NotNull
public VarsRegister getVarsRegister() {
public AndroidVarsRegistry getVarsRegister() {
return varsRegister;
}
@NotNull
public MathRegistry<Function> getFunctionsRegistry() {
return functionsRegistry;
}
// for tests
void setTimeout(int timeout) {
this.timeout = timeout;

View File

@ -83,7 +83,7 @@ public class NumberBuilder {
if (number != null) {
final String finalNumber = number;
final Var var = CollectionsUtils.get(CalculatorEngine.instance.getVarsRegister().getSystemVars(), new Finder<Var>() {
final Var var = CollectionsUtils.find(CalculatorEngine.instance.getVarsRegister().getSystemEntities(), new Finder<Var>() {
@Override
public boolean isFound(@Nullable Var var) {
return var != null && finalNumber.equals(var.getValue());

View File

@ -15,10 +15,17 @@ import org.solovyev.common.exceptions.SersoException;
*/
public class ParseException extends SersoException {
public ParseException() {
}
public ParseException(String message) {
super(message);
}
public ParseException(String message, Throwable cause) {
super(message, cause);
}
public ParseException(Throwable cause) {
super(cause);
}

View File

@ -43,7 +43,7 @@ class ToJsclTextProcessor implements TextProcessor<PreparedExpression> {
}
}
if (mathTypeBefore == MathType.function && CollectionsUtils.get(MathType.openGroupSymbols, startsWithFinder) != null) {
if (mathTypeBefore == MathType.function && CollectionsUtils.find(MathType.openGroupSymbols, startsWithFinder) != null) {
throw new ParseException("Empty function: " + mathTypeResult.getMatch());
} else if (mathTypeBefore == MathType.postfix_function && mathTypeResult.getMathType() == MathType.binary_operation) {
if ( mathTypeResult.getMatch().equals("^") ) {
@ -68,11 +68,11 @@ class ToJsclTextProcessor implements TextProcessor<PreparedExpression> {
startsWithFinder.setI(i);
int offset = 0;
String functionName = CollectionsUtils.get(MathType.function.getTokens(), startsWithFinder);
String functionName = CollectionsUtils.find(MathType.function.getTokens(), startsWithFinder);
if (functionName == null) {
String varName = CollectionsUtils.get(CalculatorEngine.instance.getVarsRegister().getVarNames(), startsWithFinder);
String varName = CollectionsUtils.find(CalculatorEngine.instance.getVarsRegister().getNames(), startsWithFinder);
if (varName != null) {
final Var var = CalculatorEngine.instance.getVarsRegister().getVar(varName);
final Var var = CalculatorEngine.instance.getVarsRegister().get(varName);
if (var != null) {
if (var.isUndefined()) {
undefinedVars.add(var);

View File

@ -10,6 +10,8 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.simpleframework.xml.Element;
import org.simpleframework.xml.Root;
import org.solovyev.common.definitions.IBuilder;
import org.solovyev.common.math.MathEntity;
import org.solovyev.common.utils.StringUtils;
/**
@ -19,7 +21,7 @@ import org.solovyev.common.utils.StringUtils;
*/
@Root
public class Var {
public class Var implements MathEntity{
@Element
@NotNull
@ -36,7 +38,7 @@ public class Var {
@Nullable
private String description;
public static class Builder {
public static class Builder implements IBuilder<Var>{
@NotNull
private String name;
@ -86,7 +88,8 @@ public class Var {
return this;
}
protected Var create () {
@NotNull
public Var create () {
final Var var = new Var();
var.name = name;
@ -101,11 +104,16 @@ public class Var {
private Var() {
}
public void copy(@NotNull Var var) {
this.name = var.name;
this.value = var.value;
this.description = var.description;
this.system = var.system;
public void copy(@NotNull MathEntity o) {
if (o instanceof Var) {
final Var that = ((Var) o);
this.name = that.name;
this.value = that.value;
this.description = that.description;
this.system = that.system;
} else {
throw new IllegalArgumentException("Trying to make a copy of unsupported type: " + o.getClass());
}
}
@Nullable

View File

@ -63,6 +63,10 @@ public class CalculatorEngineTest {
public void testEvaluate() throws Exception {
final CalculatorEngine cm = CalculatorEngine.instance;
Assert.assertEquals("0", cm.evaluate(JsclOperation.numeric, "eq(0, 1)").getResult());
Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "eq(1, 1)").getResult());
Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "eq( 1, 1)").getResult());
Assert.assertEquals("eq(1,1)", cm.evaluate(JsclOperation.simplify, "eq( 1, 1)").getResult());
Assert.assertEquals("1", cm.evaluate(JsclOperation.numeric, "lg(10)").getResult());
Assert.assertEquals("4", cm.evaluate(JsclOperation.numeric, "2+2").getResult());
Assert.assertEquals("-0.757", cm.evaluate(JsclOperation.numeric, "sin(4)").getResult());
@ -85,7 +89,7 @@ public class CalculatorEngineTest {
Assert.assertEquals("-3.41+3.41i", cm.evaluate(JsclOperation.numeric, "(5tan(2i)+2i)/(1-i)").getResult());
Assert.assertEquals("-0.1-0.2i", cm.evaluate(JsclOperation.numeric, "(1-i)/(2+6i)").getResult());
CalculatorEngine.instance.getVarsRegister().addVar(null, new Var.Builder("si", 5d));
CalculatorEngine.instance.getVarsRegister().add(null, new Var.Builder("si", 5d));
Assert.assertEquals("-0.959", cm.evaluate(JsclOperation.numeric, "sin(5)").getResult());
Assert.assertEquals("-4.795", cm.evaluate(JsclOperation.numeric, "sin(5)si").getResult());
@ -93,14 +97,14 @@ public class CalculatorEngineTest {
Assert.assertEquals("-23.973", cm.evaluate(JsclOperation.numeric, "si*sin(5)si").getResult());
Assert.assertEquals("-3.309", cm.evaluate(JsclOperation.numeric, "sisin(5si)si").getResult());
CalculatorEngine.instance.getVarsRegister().addVar(null, new Var.Builder("s", 1d));
CalculatorEngine.instance.getVarsRegister().add(null, new Var.Builder("s", 1d));
Assert.assertEquals("5", cm.evaluate(JsclOperation.numeric, "si").getResult());
CalculatorEngine.instance.getVarsRegister().addVar(null, new Var.Builder("k", 3.5d));
CalculatorEngine.instance.getVarsRegister().addVar(null, new Var.Builder("k1", 4d));
CalculatorEngine.instance.getVarsRegister().add(null, new Var.Builder("k", 3.5d));
CalculatorEngine.instance.getVarsRegister().add(null, new Var.Builder("k1", 4d));
Assert.assertEquals("4", cm.evaluate(JsclOperation.numeric, "k11").getResult());
CalculatorEngine.instance.getVarsRegister().addVar(null, new Var.Builder("t", (String) null));
CalculatorEngine.instance.getVarsRegister().add(null, new Var.Builder("t", (String) null));
Assert.assertEquals("11t", cm.evaluate(JsclOperation.numeric, "t11").getResult());
Assert.assertEquals("11et", cm.evaluate(JsclOperation.numeric, "t11e").getResult());
Assert.assertEquals("11×Infinityt", cm.evaluate(JsclOperation.numeric, "t11∞").getResult());
@ -144,7 +148,7 @@ public class CalculatorEngineTest {
}
Assert.assertEquals("0.739", cm.evaluate(JsclOperation.numeric, "cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(cos(1))))))))))))))))))))))))))))))))))))").getResult());
CalculatorEngine.instance.getVarsRegister().addVar(null, new Var.Builder("si", 5d));
CalculatorEngine.instance.getVarsRegister().add(null, new Var.Builder("si", 5d));
Assert.assertEquals("5", cm.evaluate(JsclOperation.numeric, "si").getResult());
try {

View File

@ -33,14 +33,14 @@ public class FromJsclSimplifyTextProcessorTest {
Assert.assertEquals("e", tp.process("2.718281828459045"));
Assert.assertEquals("tee", tp.process("t2.718281828459045*2.718281828459045"));
CalculatorEngine.instance.getVarsRegister().addVar(null, new Var.Builder("t2.718281828459045", "2"));
CalculatorEngine.instance.getVarsRegister().add(null, new Var.Builder("t2.718281828459045", "2"));
Assert.assertEquals("t2.718281828459045e", tp.process("t2.718281828459045*2.718281828459045"));
Assert.assertEquals("ee", tp.process("2.718281828459045*2.718281828459045"));
Assert.assertEquals("t×", tp.process("t*"));
Assert.assertEquals("×t", tp.process("*t"));
Assert.assertEquals("t×2", tp.process("t*2"));
Assert.assertEquals("2×t", tp.process("2*t"));
CalculatorEngine.instance.getVarsRegister().addVar(null, new Var.Builder("t", (String)null));
CalculatorEngine.instance.getVarsRegister().add(null, new Var.Builder("t", (String) null));
Assert.assertEquals("t×", tp.process("t*"));
Assert.assertEquals("×t", tp.process("*t"));
@ -53,7 +53,7 @@ public class FromJsclSimplifyTextProcessorTest {
Assert.assertEquals("t^[2×2t]", tp.process("t^[2*2*t]"));
Assert.assertEquals("2t^2[2t]", tp.process("2*t^2[2*t]"));
CalculatorEngine.instance.getVarsRegister().addVar(null, new Var.Builder("k", (String)null));
CalculatorEngine.instance.getVarsRegister().add(null, new Var.Builder("k", (String) null));
Assert.assertEquals("(t+2k)[k+2t]", tp.process("(t+2*k)*[k+2*t]"));
Assert.assertEquals("(te+2k)e[k+2te]", tp.process("(t*e+2*k)*e*[k+2*t*e]"));