mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-19 08:47:28 +01:00
To approximate an expression, it is more precise to approximate its simplified form than its reduced form. Indeed, we want to minimize the number of nodes in the expression before approximating. For instance, a/b has fewer nodes than a*b^-1.
133 lines
4.3 KiB
C++
133 lines
4.3 KiB
C++
#include "storage_expression_model.h"
|
|
#include "global_context.h"
|
|
#include "poincare_helpers.h"
|
|
#include <poincare/horizontal_layout.h>
|
|
#include <string.h>
|
|
#include <cmath>
|
|
#include <assert.h>
|
|
|
|
using namespace Ion;
|
|
using namespace Poincare;
|
|
|
|
namespace Shared {
|
|
|
|
StorageExpressionModel::StorageExpressionModel(Storage::Record record) :
|
|
Storage::Record(record),
|
|
m_expression(),
|
|
m_layout(),
|
|
m_circular(-1)
|
|
{
|
|
}
|
|
|
|
void StorageExpressionModel::text(char * buffer, size_t bufferSize) const {
|
|
Expression e = expressionClone();
|
|
if (e.isUninitialized() && bufferSize > 0) {
|
|
buffer[0] = 0;
|
|
} else {
|
|
e.serialize(buffer, bufferSize);
|
|
}
|
|
}
|
|
|
|
bool StorageExpressionModel::isCircularlyDefined(Poincare::Context * context) const {
|
|
if (m_circular == -1) {
|
|
m_circular = Expression::ExpressionWithoutSymbols(expressionClone(), *context).isUninitialized();
|
|
}
|
|
return m_circular;
|
|
}
|
|
|
|
Expression StorageExpressionModel::expressionReduced(Poincare::Context * context) const {
|
|
if (m_expression.isUninitialized()) {
|
|
assert(!isNull());
|
|
Ion::Storage::Record::Data recordData = value();
|
|
m_expression = Expression::ExpressionFromAddress(expressionAddressForValue(recordData), expressionSizeForValue(recordData));
|
|
PoincareHelpers::Simplify(&m_expression, *context);
|
|
// simplify might return an uninitialized Expression if interrupted
|
|
if (m_expression.isUninitialized()) {
|
|
m_expression = Expression::ExpressionFromAddress(expressionAddressForValue(recordData), expressionSizeForValue(recordData));
|
|
}
|
|
}
|
|
return m_expression;
|
|
}
|
|
|
|
Expression StorageExpressionModel::expressionClone() const {
|
|
assert(!isNull());
|
|
Ion::Storage::Record::Data recordData = value();
|
|
/* A new Expression has to be created at each call (because it might be tempered with after calling) */
|
|
return Expression::ExpressionFromAddress(expressionAddressForValue(recordData), expressionSizeForValue(recordData));
|
|
}
|
|
|
|
Layout StorageExpressionModel::layout() {
|
|
if (m_layout.isUninitialized()) {
|
|
m_layout = PoincareHelpers::CreateLayout(expressionClone());
|
|
if (m_layout.isUninitialized()) {
|
|
m_layout = HorizontalLayout();
|
|
}
|
|
}
|
|
return m_layout;
|
|
}
|
|
|
|
bool StorageExpressionModel::isDefined() {
|
|
return !isEmpty();
|
|
}
|
|
|
|
bool StorageExpressionModel::isEmpty() {
|
|
return value().size <= metaDataSize();
|
|
}
|
|
|
|
void StorageExpressionModel::tidy() {
|
|
m_layout = Layout();
|
|
m_expression = Expression();
|
|
m_circular = 0;
|
|
}
|
|
|
|
Ion::Storage::Record::ErrorStatus StorageExpressionModel::setContent(const char * c) {
|
|
Expression expressionToStore;
|
|
// if c = "", we want to reinit the Expression
|
|
if (c && *c != 0) {
|
|
// Compute the expression to store, without replacing symbols
|
|
expressionToStore = Expression::Parse(c);
|
|
if (!expressionToStore.isUninitialized()) {
|
|
Symbol xUnknown = Symbol(Symbol::SpecialSymbols::UnknownX);
|
|
expressionToStore = expressionToStore.replaceSymbolWithExpression(Symbol("x", 1), xUnknown);
|
|
}
|
|
}
|
|
return setExpressionContent(expressionToStore);
|
|
}
|
|
|
|
Ion::Storage::Record::ErrorStatus StorageExpressionModel::setExpressionContent(Expression & expressionToStore) {
|
|
assert(!isNull());
|
|
// Prepare the new data to store
|
|
Ion::Storage::Record::Data newData = value();
|
|
size_t expressionToStoreSize = expressionToStore.isUninitialized() ? 0 : expressionToStore.size();
|
|
newData.size = metaDataSize() + expressionToStoreSize;
|
|
|
|
// Set the data
|
|
Ion::Storage::Record::ErrorStatus error = setValue(newData);
|
|
if (error != Ion::Storage::Record::ErrorStatus::None) {
|
|
assert(error == Ion::Storage::Record::ErrorStatus::NotEnoughSpaceAvailable);
|
|
return error;
|
|
}
|
|
|
|
// Copy the expression if needed
|
|
if (!expressionToStore.isUninitialized()) {
|
|
memcpy(expressionAddressForValue(value()), expressionToStore.addressInPool(), expressionToStore.size());
|
|
}
|
|
/* We cannot call tidy here because tidy is a virtual function and does not
|
|
* do the same thing for all children class. And here we want to delete only
|
|
* the m_layout and m_expression. */
|
|
m_layout = Layout();
|
|
m_expression = Expression();
|
|
m_circular = 0;
|
|
return error;
|
|
}
|
|
|
|
void * StorageExpressionModel::expressionAddressForValue(Ion::Storage::Record::Data recordData) const {
|
|
return (char *)recordData.buffer+metaDataSize();
|
|
}
|
|
|
|
size_t StorageExpressionModel::expressionSizeForValue(Ion::Storage::Record::Data recordData) const {
|
|
return recordData.size-metaDataSize();
|
|
}
|
|
|
|
}
|