[poincare] SymbolAbstract is parent of Symbol and Function

This commit is contained in:
Léa Saviot
2018-10-08 12:05:39 +02:00
committed by Émilie Feral
parent c3043f47d4
commit 6197ebd4c5
15 changed files with 139 additions and 66 deletions

View File

@@ -9,8 +9,8 @@ using namespace Shared;
namespace Regression {
const Expression RegressionContext::expressionForSymbol(const Symbol & symbol) {
if (Symbol::isRegressionSymbol(symbol.name())) {
const Expression RegressionContext::expressionForSymbol(const SymbolAbstract & symbol) {
if (symbol.type() == ExpressionNode::Type::Symbol && Symbol::isRegressionSymbol(symbol.name())) {
const char * seriesName = symbol.name();
assert(strlen(seriesName) == 2);
@@ -23,9 +23,9 @@ const Expression RegressionContext::expressionForSymbol(const Symbol & symbol) {
assert(m_seriesPairIndex >= 0);
assert(m_seriesPairIndex < m_store->numberOfPairsOfSeries(series));
return Float<double>(m_store->get(series, storeI, m_seriesPairIndex));
} else {
return m_parentContext->expressionForSymbol(symbol);
}
} else {
return m_parentContext->expressionForSymbol(symbol);
}
}

View File

@@ -15,10 +15,12 @@ CacheContext<T>::CacheContext(Context * parentContext) :
}
template<typename T>
const Expression CacheContext<T>::expressionForSymbol(const Symbol & symbol) {
const Expression CacheContext<T>::expressionForSymbol(const SymbolAbstract & symbol) {
// [u|v](n(+1)?)
if ((symbol.name()[0] == SequenceStore::k_sequenceNames[0][0] || symbol.name()[0] == SequenceStore::k_sequenceNames[1][0])
&& (strcmp(symbol.name()+1, "(n)") == 0 || strcmp(symbol.name()+1, "(n+1)") == 0)) {
if (symbol.type() == ExpressionNode::Type::Symbol
&& (symbol.name()[0] == SequenceStore::k_sequenceNames[0][0] || symbol.name()[0] == SequenceStore::k_sequenceNames[1][0])
&& (strcmp(symbol.name()+1, "(n)") == 0 || strcmp(symbol.name()+1, "(n+1)") == 0))
{
return Float<T>(m_values[nameIndexForSymbol(symbol)][rankIndexForSymbol(symbol)]);
}
return VariableContext::expressionForSymbol(symbol);

View File

@@ -9,8 +9,8 @@ using namespace Shared;
namespace Statistics {
const Expression StatisticsContext::expressionForSymbol(const Symbol & symbol) {
if (Symbol::isSeriesSymbol(symbol.name())) {
const Expression StatisticsContext::expressionForSymbol(const SymbolAbstract & symbol) {
if (symbol.type() == ExpressionNode::Type::Symbol && Symbol::isSeriesSymbol(symbol.name())) {
const char * seriesName = symbol.name();
assert(strlen(seriesName) == 2);

View File

@@ -120,6 +120,7 @@ objs += $(addprefix poincare/src/,\
subtraction.o\
sum.o\
symbol.o\
symbol_abstract.o\
tangent.o\
tree_handle.o\
tree_node.o\

View File

@@ -4,11 +4,12 @@
namespace Poincare {
class Expression;
class Symbol;
class SymbolAbstract;
class Symbol; //TODO remove?
class Context {
public:
virtual const Expression expressionForSymbol(const Symbol & symbol) = 0;
virtual const Expression expressionForSymbol(const SymbolAbstract & symbol) = 0;
virtual void setExpressionForSymbol(const Expression & expression, const Symbol & symbol, Context & context) = 0;
};

View File

@@ -1,14 +1,18 @@
#ifndef POINCARE_FUNCTION_H
#define POINCARE_FUNCTION_H
#include <poincare/symbol.h>
#include <poincare/symbol_abstract.h>
#include <poincare/variable_context.h>
namespace Poincare {
class FunctionNode : public SymbolNode {
class FunctionNode : public SymbolAbstractNode {
public:
// SymbolAbstractNode
const char * name() const override { return m_name; }
// TreeNode
void initToMatchSize(size_t goalSize) override;
size_t size() const override;
int numberOfChildren() const override { return 1; } //TODO allow any number of children? Needs templating
#if POINCARE_TREE_LOG
@@ -19,6 +23,7 @@ public:
// Properties
Type type() const override { return Type::Function; }
Sign sign() const override { return Sign::Unknown; }
Expression replaceSymbolWithExpression(const Symbol & symbol, const Expression & expression) override;
int polynomialDegree(Context & context, const char * symbolName) const override;
int getPolynomialCoefficients(Context & context, const char * symbolName, Expression coefficients[]) const override;
@@ -26,6 +31,8 @@ public:
float characteristicXRange(Context & context, Preferences::AngleUnit angleUnit) const override;
private:
char m_name[0]; // MUST be the last member variable
VariableContext xContext(Context & parentContext) const;
// Layout
Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
@@ -37,10 +44,10 @@ private:
Evaluation<double> approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override;
};
class Function : public Symbol {
class Function : public SymbolAbstract {
public:
explicit Function(const char * name);
Function(const FunctionNode * n) : Symbol(n) {}
Function(const FunctionNode * n) : SymbolAbstract(n) {}
explicit Function(const char * name, Expression operand) : Function(name) {
replaceChildAtIndexInPlace(0, operand);
}

View File

@@ -19,7 +19,7 @@ public:
static constexpr char expExtension[] = "exp";
/* The expression recorded in global context is already a expression.
* Otherwise, we would need the context and the angle unit to evaluate it */
const Expression expressionForSymbol(const Symbol & symbol) override;
const Expression expressionForSymbol(const SymbolAbstract & symbol) override;
void setExpressionForSymbol(const Expression & expression, const Symbol & symbol, Context & context) override;
static Ion::Storage::Record RecordWithName(const char * name);
static bool storageMemoryFull();

View File

@@ -1,30 +1,16 @@
#ifndef POINCARE_SYMBOL_H
#define POINCARE_SYMBOL_H
#include <poincare/expression.h>
#include <poincare/symbol_abstract.h>
namespace Poincare {
/* TODO: should we keep the size of SymbolNode as a member to speed up TreePool
* scan? */
/* Symbol Node contains an empty member variable "m_name", which is used to get
* the string that follows. This means that a SymbolNode's size is sizeo
* (SymbolNode) + strlen(string).
*
* Seen by TreePool: |SymbolNode |
* SymbolNode layout: |ExpressionNode|m_name| |
* Memory content: |ExpressionNode|S |y|m|b|o|l|N|a|m|e|0|
* */
class SymbolNode final : public ExpressionNode {
friend class Store;
class SymbolNode final : public SymbolAbstractNode {
public:
void initToMatchSize(size_t goalSize) override;
void setName(const char * name, int length) { strlcpy(m_name, name, length+1); }
const char * name() const { return m_name; }
const char * name() const override { return m_name; }
// TreeNode
void initToMatchSize(size_t goalSize) override;
size_t size() const override;
int numberOfChildren() const override { return 0; }
#if POINCARE_TREE_LOG
@@ -45,10 +31,7 @@ public:
int getVariables(Context & context, isVariableTest isVariable, char * variables, int maxSizeVariable) const override;
float characteristicXRange(Context & context, Preferences::AngleUnit angleUnit) const override;
/* Comparison */
int simplificationOrderSameType(const ExpressionNode * e, bool canBeInterrupted) const override;
/* Layout */
/* Layout */
Layout createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
@@ -64,14 +47,14 @@ public:
bool isPi() const { return isSymbolChar(Ion::Charset::SmallPi); }
bool isExponential() const { return isSymbolChar(Ion::Charset::Exponential); }
bool isIComplex() const { return isSymbolChar(Ion::Charset::IComplex); }
protected:
char m_name[0]; // MUST be the last member variable
private:
char m_name[0]; // MUST be the last member variable
template<typename T> Evaluation<T> templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const;
bool isSymbolChar(char c) const { const char symbolName[2] = {c, 0}; return strcmp(m_name, symbolName) == 0; }
};
class Symbol final : public Expression {
class Symbol final : public SymbolAbstract {
friend class Expression;
friend class Store;
public:
@@ -83,7 +66,7 @@ public:
};
Symbol(const char * name, int length);
Symbol(char name);
Symbol(const SymbolNode * node) : Expression(node) {}
Symbol(const SymbolNode * node) : SymbolAbstract(node) {}
// Symbol properties
bool isPi() const { return node()->isPi(); }
@@ -97,9 +80,6 @@ public:
Expression shallowReduce(Context & context, Preferences::AngleUnit angleUnit, bool replaceSymbols = true);
Expression replaceSymbolWithExpression(const Symbol & symbol, const Expression & expression);
int getPolynomialCoefficients(Context & context, const char * symbolName, Expression coefficients[]) const;
// Symbol
const char * name() const { return node()->name(); }
private:
SymbolNode * node() const { return static_cast<SymbolNode *>(Expression::node()); }
};

View File

@@ -0,0 +1,53 @@
#ifndef POINCARE_ABSTRACT_SYMBOL_H
#define POINCARE_ABSTRACT_SYMBOL_H
#include <poincare/expression.h>
namespace Poincare {
/* TODO: should we keep the size of SymbolAbstractNode as a member to speed up
* TreePool scan? */
/* SymbolAbstract derived classes must have a char[0] member variable as their
* last member variable, so they can access their name, which is the string that
* follows the node in memory.
* This means that a DerivedSymbolNode's size is sizeof(DerivedSymbolNode) +
* strlen(string).
*
* For instance:
* Seen by TreePool: |SymbolNode |
* SymbolNode layout: |ExpressionNode|m_name| |
* Memory content: |ExpressionNode|S |y|m|b|o|l|N|a|m|e|0|
* */
class SymbolAbstractNode : public ExpressionNode {
friend class Store;
public:
virtual const char * name() const = 0;
void setName(const char * newName, int length);
// ExpressionNode
int simplificationOrderSameType(const ExpressionNode * e, bool canBeInterrupted) const override;
// TreeNode
#if POINCARE_TREE_LOG
virtual void logNodeName(std::ostream & stream) const override {
stream << "SymbolAbstract";
}
#endif
protected:
void initName(size_t nameSize);
};
class SymbolAbstract : public Expression {
public:
const char * name() const { return node()->name(); }
protected:
SymbolAbstract(const SymbolAbstractNode * node) : Expression(node) {}
SymbolAbstractNode * node() const { return static_cast<SymbolAbstractNode *>(Expression::node()); }
};
}
#endif

View File

@@ -14,7 +14,7 @@ public:
// Context
void setExpressionForSymbol(const Expression & expression, const Symbol & symbol, Context & context) override;
const Expression expressionForSymbol(const Symbol & symbol) override;
const Expression expressionForSymbol(const SymbolAbstract & symbol) override;
private:
const char * m_name;

View File

@@ -5,6 +5,7 @@
#include <poincare/rational.h>
#include <poincare/serialization_helper.h>
#include <poincare/simplification_helper.h>
#include <poincare/symbol.h>
#include <cmath>
namespace Poincare {
@@ -15,6 +16,15 @@ static size_t NodeSize(size_t nameLength) {
return Helpers::AlignedSize(sizeof(FunctionNode)+nameLength+1, 4);
}
void FunctionNode::initToMatchSize(size_t goalSize) {
// TODO Factorize with symbol
assert(goalSize != sizeof(FunctionNode));
assert(goalSize > sizeof(FunctionNode));
size_t nameSize = goalSize - sizeof(FunctionNode);
SymbolAbstractNode::initName(nameSize);
assert(size() == goalSize);
}
size_t FunctionNode::size() const {
return NodeSize(strlen(m_name));
}
@@ -109,7 +119,7 @@ Expression Function::replaceSymbolWithExpression(const Symbol & symbol, const Ex
if (symbol.type() == ExpressionNode::Type::Function && strcmp(name(), symbol.name()) == 0) {
Expression value = expression.clone();
// Replace the unknown in the new expression by the function's child
const char x[2] = {SpecialSymbols::UnknownX, 0};
const char x[2] = {Symbol::SpecialSymbols::UnknownX, 0};
Symbol xSymbol = Symbol(x, 1);
Expression xValue = childAtIndex(0);
value.replaceSymbolWithExpression(xSymbol, xValue);

View File

@@ -22,13 +22,16 @@ bool GlobalContext::storageMemoryFull() {
/**/
const Expression GlobalContext::expressionForSymbol(const Symbol & symbol) {
// Constant symbols
if (symbol.isPi()) {
return Float<double>(M_PI);
}
if (symbol.isExponential()) {
return Float<double>(M_E);
const Expression GlobalContext::expressionForSymbol(const SymbolAbstract & symbol) {
if (symbol.type() == ExpressionNode::Type::Symbol) {
// Constant symbols
Symbol s = static_cast<const Symbol &>(symbol);
if (s.isPi()) {
return Float<double>(M_PI);
}
if (s.isExponential()) {
return Float<double>(M_E);
}
}
// Look up the file system for symbol
return Expression::ExpressionFromRecord(RecordWithName(symbol.name()));

View File

@@ -17,11 +17,9 @@ constexpr char Symbol::k_ans[];
void SymbolNode::initToMatchSize(size_t goalSize) {
assert(goalSize != sizeof(SymbolNode));
int nameSize = goalSize - sizeof(SymbolNode);
for (int i = 0; i < nameSize - 1; i++) {
m_name[i] = 'a';
}
m_name[nameSize-1] = 0;
assert(goalSize > sizeof(SymbolNode));
size_t nameSize = goalSize - sizeof(SymbolNode);
SymbolAbstractNode::initName(nameSize);
assert(size() == goalSize);
}
@@ -99,11 +97,6 @@ float SymbolNode::characteristicXRange(Context & context, Preferences::AngleUnit
return 0.0;
}
int SymbolNode::simplificationOrderSameType(const ExpressionNode * e, bool canBeInterrupted) const {
assert(e->type() == Type::Symbol);
return strcmp(m_name, static_cast<const SymbolNode *>(e)->name());
}
Layout SymbolNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {
if (m_name[0] == Symbol::SpecialSymbols::UnknownX) {
assert(m_name[1] == 0);
@@ -172,7 +165,7 @@ Evaluation<T> SymbolNode::templatedApproximate(Context& context, Preferences::An
return e.approximateToEvaluation<T>(context, angleUnit);
}
Symbol::Symbol(const char * name, int length) : Expression(TreePool::sharedPool()->createTreeNode<SymbolNode>(NodeSize(length))) {
Symbol::Symbol(const char * name, int length) : SymbolAbstract(TreePool::sharedPool()->createTreeNode<SymbolNode>(NodeSize(length))) {
node()->setName(name, length);
}

View File

@@ -0,0 +1,23 @@
#include <poincare/symbol_abstract.h>
#include <string.h>
namespace Poincare {
void SymbolAbstractNode::setName(const char * newName, int length) {
strlcpy(const_cast<char*>(name()), newName, length+1);
}
int SymbolAbstractNode::simplificationOrderSameType(const ExpressionNode * e, bool canBeInterrupted) const {
assert(e->type() == Type::Symbol || e->type() == Type::Function);
return strcmp(name(), static_cast<const SymbolAbstractNode *>(e)->name());
}
void SymbolAbstractNode::initName(size_t nameSize) {
char * modifiableName = const_cast<char *>(name());
for (int i = 0; i < nameSize - 1; i++) {
modifiableName[i] = 'a';
}
modifiableName[nameSize-1] = 0;
}
}

View File

@@ -29,7 +29,7 @@ void VariableContext::setExpressionForSymbol(const Expression & expression, cons
}
}
const Expression VariableContext::expressionForSymbol(const Symbol & symbol) {
const Expression VariableContext::expressionForSymbol(const SymbolAbstract & symbol) {
if (strcmp(symbol.name(), m_name) == 0) {
return m_value;
} else {