[shared] Create ExpiringPointer: in DEBUG, check that pointers to

memoized functions are not used when invalid
This commit is contained in:
Émilie Feral
2018-10-23 17:46:15 +02:00
parent 8e6cff9572
commit e8b58a2b5b
29 changed files with 108 additions and 49 deletions

View File

@@ -41,7 +41,7 @@ float GraphController::interestingXRange() {
float characteristicRange = 0.0f;
TextFieldDelegateApp * myApp = (TextFieldDelegateApp *)app();
for (int i = 0; i < functionStore()->numberOfActiveFunctions(); i++) {
StorageFunction * f = functionStore()->modelForRecord(functionStore()->activeRecordAtIndex(i));
ExpiringPointer<StorageCartesianFunction> f = functionStore()->modelForRecord(functionStore()->activeRecordAtIndex(i));
float fRange = f->expression(myApp->localContext()).characteristicXRange(*(myApp->localContext()), Poincare::Preferences::sharedPreferences()->angleUnit());
if (!std::isnan(fRange)) {
characteristicRange = fRange > characteristicRange ? fRange : characteristicRange;
@@ -56,7 +56,7 @@ int GraphController::estimatedBannerNumberOfLines() const {
void GraphController::selectFunctionWithCursor(int functionIndex) {
StorageFunctionGraphController::selectFunctionWithCursor(functionIndex);
StorageCartesianFunction * f = functionStore()->modelForRecord(functionStore()->activeRecordAtIndex(indexFunctionSelectedByCursor()));
ExpiringPointer<StorageCartesianFunction> f = functionStore()->modelForRecord(functionStore()->activeRecordAtIndex(indexFunctionSelectedByCursor()));
m_cursorView.setColor(f->color());
}

View File

@@ -9,7 +9,7 @@ using namespace Poincare;
namespace Graph {
bool GraphControllerHelper::privateMoveCursorHorizontally(Shared::CurveViewCursor * cursor, int direction, Shared::InteractiveCurveViewRange * range, int numberOfStepsInGradUnit, Ion::Storage::Record record, App * app, float cursorTopMarginRatio, float cursorRightMarginRatio, float cursorBottomMarginRatio, float cursorLeftMarginRatio) {
StorageCartesianFunction * function = app->functionStore()->modelForRecord(record);
ExpiringPointer<StorageCartesianFunction> function = app->functionStore()->modelForRecord(record);
double xCursorPosition = cursor->x();
double x = direction > 0 ? xCursorPosition + range->xGridUnit()/numberOfStepsInGradUnit : xCursorPosition - range->xGridUnit()/numberOfStepsInGradUnit;
double y = function->evaluateAtAbscissa(x, app->localContext());
@@ -19,7 +19,7 @@ bool GraphControllerHelper::privateMoveCursorHorizontally(Shared::CurveViewCurso
}
void GraphControllerHelper::reloadDerivativeInBannerViewForCursorOnFunction(Shared::CurveViewCursor * cursor, Ion::Storage::Record record, App * app) {
StorageCartesianFunction * function = app->functionStore()->modelForRecord(record);
ExpiringPointer<StorageCartesianFunction> function = app->functionStore()->modelForRecord(record);
constexpr size_t bufferSize = FunctionBannerDelegate::k_maxNumberOfCharacters+PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits);
char buffer[bufferSize];
const char * space = " ";

View File

@@ -25,7 +25,7 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const {
StorageFunctionGraphView::drawRect(ctx, rect);
for (int i = 0; i < m_functionStore->numberOfActiveFunctions(); i++) {
Ion::Storage::Record record = m_functionStore->activeRecordAtIndex(i);
StorageCartesianFunction * f = m_functionStore->modelForRecord(record);;
ExpiringPointer<StorageCartesianFunction> f = m_functionStore->modelForRecord(record);;
/* Draw function (color the area under curve of the selected function) */
if (record == m_selectedRecord) {
@@ -33,13 +33,13 @@ void GraphView::drawRect(KDContext * ctx, KDRect rect) const {
StorageCartesianFunction * f = (StorageCartesianFunction *)model;
Poincare::Context * c = (Poincare::Context *)context;
return f->evaluateAtAbscissa(t, c);
}, f, context(), f->color(), true, m_highlightedStart, m_highlightedEnd);
}, f.operator->(), context(), f->color(), true, m_highlightedStart, m_highlightedEnd);
} else {
drawCurve(ctx, rect, [](float t, void * model, void * context) {
StorageCartesianFunction * f = (StorageCartesianFunction *)model;
Poincare::Context * c = (Poincare::Context *)context;
return f->evaluateAtAbscissa(t, c);
}, f, context(), f->color());
}, f.operator->(), context(), f->color());
}
/* Draw tangent */

View File

@@ -36,7 +36,7 @@ double IntegralGraphController::cursorNextStep(double x, int direction) {
return (direction > 0 ? x + m_graphRange->xGridUnit()/k_numberOfCursorStepsInGradUnit : x - m_graphRange->xGridUnit()/k_numberOfCursorStepsInGradUnit);
}
Layout IntegralGraphController::createFunctionLayout(StorageFunction * function) {
Layout IntegralGraphController::createFunctionLayout(ExpiringPointer<StorageFunction> function) {
constexpr size_t bufferSize = SymbolAbstract::k_maxNameSize+5; // f(x)dx
char buffer[bufferSize];
const char * dx = "dx";

View File

@@ -14,7 +14,7 @@ public:
private:
I18n::Message legendMessageAtStep(Step step) override;
double cursorNextStep(double position, int direction) override;
Poincare::Layout createFunctionLayout(Shared::StorageFunction * function) override;
Poincare::Layout createFunctionLayout(Shared::ExpiringPointer<Shared::StorageFunction> function) override;
};
}

View File

@@ -24,11 +24,11 @@ void IntersectionGraphController::reloadBannerView() {
const char * space = " ";
const char * legend = "=";
// 'f(x)=g(x)=', keep 2 chars for '='
StorageCartesianFunction * f = functionStore()->modelForRecord(m_record);
ExpiringPointer<StorageCartesianFunction> f = functionStore()->modelForRecord(m_record);
int numberOfChar = f->nameWithArgument(buffer, bufferSize-2, StorageCartesianFunctionStore::Symbol());
numberOfChar += strlcpy(buffer+numberOfChar, legend, bufferSize-numberOfChar);
// keep 1 char for '=';
StorageCartesianFunction * g = functionStore()->modelForRecord(m_intersectedRecord);
ExpiringPointer<StorageCartesianFunction> g = functionStore()->modelForRecord(m_intersectedRecord);
numberOfChar += g->nameWithArgument(buffer, bufferSize-numberOfChar-1, StorageCartesianFunctionStore::Symbol());
numberOfChar += strlcpy(buffer+numberOfChar, legend, bufferSize-numberOfChar);
numberOfChar += PoincareHelpers::ConvertFloatToText<double>(m_cursor->y(), buffer+numberOfChar, bufferSize-numberOfChar, Constant::MediumNumberOfSignificantDigits);

View File

@@ -46,7 +46,7 @@ void TangentGraphController::reloadBannerView() {
char buffer[bufferSize];
const char * legend = "a=";
int legendLength = strlcpy(buffer, legend, bufferSize);
StorageCartesianFunction * function = myApp->functionStore()->modelForRecord(m_record);
ExpiringPointer<StorageCartesianFunction> function = myApp->functionStore()->modelForRecord(m_record);
double y = function->approximateDerivative(m_cursor->x(), myApp->localContext());
PoincareHelpers::ConvertFloatToText<double>(y, buffer + legendLength, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::MediumNumberOfSignificantDigits), Constant::MediumNumberOfSignificantDigits);
m_bannerView->setLegendAtIndex(buffer, 4);

View File

@@ -92,7 +92,7 @@ bool StorageListController::textFieldDidFinishEditing(TextField * textField, con
}
bool StorageListController::textFieldDidAbortEditing(TextField * textField) {
StorageFunction * function = modelStore()->modelForRecord(modelStore()->recordAtIndex(selectedRow()));
ExpiringPointer<StorageFunction> function = modelStore()->modelForRecord(modelStore()->recordAtIndex(selectedRow()));
setFunctionNameInTextField(function, textField);
m_selectableTableView.selectedCell()->setHighlighted(true);
app()->setFirstResponder(&m_selectableTableView);
@@ -124,7 +124,7 @@ HighlightCell * StorageListController::expressionCells(int index) {
void StorageListController::willDisplayTitleCellAtIndex(HighlightCell * cell, int j) {
TextFieldFunctionTitleCell * titleCell = static_cast<TextFieldFunctionTitleCell *>(cell);
if (!titleCell->isEditing()) {
StorageFunction * function = modelStore()->modelForRecord(modelStore()->recordAtIndex(j));
ExpiringPointer<StorageFunction> function = modelStore()->modelForRecord(modelStore()->recordAtIndex(j));
setFunctionNameInTextField(function, titleCell->textField());
KDColor functionNameColor = function->isActive() ? function->color() : Palette::GreyDark;
titleCell->setColor(functionNameColor);
@@ -134,12 +134,12 @@ void StorageListController::willDisplayTitleCellAtIndex(HighlightCell * cell, in
void StorageListController::willDisplayExpressionCellAtIndex(HighlightCell * cell, int j) {
Shared::StorageFunctionListController::willDisplayExpressionCellAtIndex(cell, j);
FunctionExpressionCell * myCell = (FunctionExpressionCell *)cell;
StorageFunction * f = modelStore()->modelForRecord(modelStore()->recordAtIndex(j));
ExpiringPointer<StorageFunction> f = modelStore()->modelForRecord(modelStore()->recordAtIndex(j));
KDColor textColor = f->isActive() ? KDColorBlack : Palette::GreyDark;
myCell->setTextColor(textColor);
}
void StorageListController::setFunctionNameInTextField(StorageFunction * function, TextField * textField) {
void StorageListController::setFunctionNameInTextField(ExpiringPointer<StorageFunction> function, TextField * textField) {
char bufferName[BufferTextView::k_maxNumberOfChar];
function->nameWithArgument(bufferName, BufferTextView::k_maxNumberOfChar, modelStore()->symbol());
textField->setText(bufferName);

View File

@@ -31,7 +31,7 @@ private:
Shared::TextFieldDelegateApp * textFieldDelegateApp() override {
return static_cast<Shared::TextFieldDelegateApp *>(app());
}
void setFunctionNameInTextField(Shared::StorageFunction * function, TextField * textField);
void setFunctionNameInTextField(Shared::ExpiringPointer<Shared::StorageFunction> function, TextField * textField);
TextFieldFunctionTitleCell m_functionTitleCells[k_maxNumberOfDisplayableRows];
Shared::FunctionExpressionCell m_expressionCells[k_maxNumberOfDisplayableRows];
ListParameterController m_parameterController;

View File

@@ -10,7 +10,7 @@ namespace Graph {
class StorageCartesianFunctionStore : public Shared::StorageFunctionStore {
public:
Shared::StorageCartesianFunction * modelForRecord(Ion::Storage::Record record) const override { return static_cast<Shared::StorageCartesianFunction *>(Shared::StorageFunctionStore::modelForRecord(record)); }
Shared::ExpiringPointer<Shared::StorageCartesianFunction> modelForRecord(Ion::Storage::Record record) const { return Shared::ExpiringPointer<Shared::StorageCartesianFunction>(static_cast<Shared::StorageCartesianFunction *>(privateModelForRecord(record))); }
static char Symbol() { return 'x'; }
char symbol() const override { return Symbol(); }
private:

View File

@@ -69,7 +69,7 @@ void StorageFunctionParameterController::willDisplayCellForIndex(HighlightCell *
}
}
StorageCartesianFunction * StorageFunctionParameterController::function() {
ExpiringPointer<StorageCartesianFunction> StorageFunctionParameterController::function() {
App * a = static_cast<App *>(app());
return a->functionStore()->modelForRecord(m_record);
}

View File

@@ -1,6 +1,7 @@
#ifndef GRAPH_STORAGE_FUNCTION_PARAM_CONTROLLER_H
#define GRAPH_STORAGE_FUNCTION_PARAM_CONTROLLER_H
#include "../../shared/expiring_pointer.h"
#include "../../shared/storage_cartesian_function.h"
#include "../../shared/storage_values_function_parameter_controller.h"
@@ -18,7 +19,7 @@ public:
void willDisplayCellForIndex(HighlightCell * cell, int index) override;
void viewWillAppear() override;
private:
Shared::StorageCartesianFunction * function();
Shared::ExpiringPointer<Shared::StorageCartesianFunction> function();
#if COPY_COLUMN
constexpr static int k_totalNumberOfCell = 2;
#else

View File

@@ -41,7 +41,7 @@ void StorageValuesController::willDisplayCellAtLocation(HighlightCell * cell, in
// The cell is a function title cell:
if (j == 0 && i > 0) {
Shared::BufferFunctionTitleCell * myFunctionCell = (Shared::BufferFunctionTitleCell *)cell;
Shared::StorageCartesianFunction * function = functionStore()->modelForRecord(recordAtColumn(i));
Shared::ExpiringPointer<StorageCartesianFunction> function = functionStore()->modelForRecord(recordAtColumn(i));
const size_t bufferNameSize = Shared::StorageFunction::k_maxNameWithArgumentSize + 1;
char bufferName[bufferNameSize];
if (isDerivativeColumn(i)) {
@@ -70,7 +70,7 @@ Ion::Storage::Record StorageValuesController::recordAtColumn(int i) {
int index = 1;
for (int k = 0; k < functionStore()->numberOfDefinedModels(); k++) {
Ion::Storage::Record record = functionStore()->definedRecordAtIndex(k);
StorageCartesianFunction * f = functionStore()->modelForRecord(record);
ExpiringPointer<StorageCartesianFunction> f = functionStore()->modelForRecord(record);
if (f->isActive()) {
if (i == index) {
return record;
@@ -92,7 +92,7 @@ bool StorageValuesController::isDerivativeColumn(int i) {
assert(i >= 1);
int index = 1;
for (int k = 0; k < functionStore()->numberOfDefinedModels(); k++) {
StorageCartesianFunction * f = functionStore()->modelForRecord(functionStore()->definedRecordAtIndex(k));
ExpiringPointer<StorageCartesianFunction> f = functionStore()->modelForRecord(functionStore()->definedRecordAtIndex(k));
if (f->isActive()) {
if (i == index) {
return false;
@@ -139,7 +139,7 @@ StorageFunctionParameterController * StorageValuesController::functionParameterC
}
double StorageValuesController::evaluationOfAbscissaAtColumn(double abscissa, int columnIndex) {
Shared::StorageCartesianFunction * function = functionStore()->modelForRecord(recordAtColumn(columnIndex));
Shared::ExpiringPointer<StorageCartesianFunction> function = functionStore()->modelForRecord(recordAtColumn(columnIndex));
TextFieldDelegateApp * myApp = (TextFieldDelegateApp *)app();
if (isDerivativeColumn(columnIndex)) {
return function->approximateDerivative(abscissa, myApp->localContext());
@@ -150,7 +150,7 @@ double StorageValuesController::evaluationOfAbscissaAtColumn(double abscissa, in
void StorageValuesController::updateNumberOfColumns() {
int result = 1;
for (int i = 0; i < functionStore()->numberOfActiveFunctions(); i++) {
StorageCartesianFunction * f = functionStore()->modelForRecord(functionStore()->activeRecordAtIndex(i));
ExpiringPointer<StorageCartesianFunction> f = functionStore()->modelForRecord(functionStore()->activeRecordAtIndex(i));
if (f->isActive()) {
result += 1 + f->displayDerivative();
}

View File

@@ -9,6 +9,7 @@ app_objs += $(addprefix apps/shared/,\
curve_view_range.o\
double_pair_store.o\
editable_cell_table_view_controller.o\
expiring_pointer.o\
expression_field_delegate_app.o\
expression_model.o\
expression_model_list_controller.o\

View File

@@ -0,0 +1,17 @@
#include "expiring_pointer.h"
#include "storage_expression_model.h"
#include "storage_cartesian_function.h"
#include "storage_function.h"
namespace Shared {
#if DEBUG
template<>
StorageExpressionModel * ExpiringPointer<StorageExpressionModel>::s_global = nullptr;
template<>
StorageFunction * ExpiringPointer<StorageFunction>::s_global = nullptr;
template<>
StorageCartesianFunction * ExpiringPointer<StorageCartesianFunction>::s_global = nullptr;
#endif
}

View File

@@ -0,0 +1,37 @@
#ifndef SHARED_EXPIRING_POINTER_H
#define SHARED_EXPIRING_POINTER_H
#include <escher.h>
namespace Shared {
template <class T>
class ExpiringPointer {
public:
ExpiringPointer(T * rawPointer, bool reinitGlobal = true) : m_rawPointer(rawPointer) {
#if DEBUG
s_global = rawPointer;
#endif
}
T *operator->() {
#if DEBUG
assert(m_rawPointer != nullptr && m_rawPointer == s_global);
#endif
return m_rawPointer;
}
T &operator*() {
#if DEBUG
assert(m_rawPointer != nullptr && m_rawPointer == s_global);
#endif
return *m_rawPointer;
}
private:
#if DEBUG
static T * s_global;
#endif
T * m_rawPointer;
};
}
#endif

View File

@@ -19,7 +19,7 @@ KDCoordinate StorageExpressionModelListController::expressionRowHeight(int j) {
if (isAddEmptyRow(j)) {
return Metric::StoreRowHeight;
}
StorageExpressionModel * m = modelStore()->modelForRecord(modelStore()->recordAtIndex(j));
ExpiringPointer<StorageExpressionModel> m = modelStore()->modelForRecord(modelStore()->recordAtIndex(j));
if (m->layout().isUninitialized()) {
return Metric::StoreRowHeight;
}
@@ -30,7 +30,7 @@ KDCoordinate StorageExpressionModelListController::expressionRowHeight(int j) {
void StorageExpressionModelListController::willDisplayExpressionCellAtIndex(HighlightCell * cell, int j) {
EvenOddExpressionCell * myCell = (EvenOddExpressionCell *)cell;
StorageExpressionModel * m = modelStore()->modelForRecord(modelStore()->recordAtIndex(j));
ExpiringPointer<StorageExpressionModel> m = modelStore()->modelForRecord(modelStore()->recordAtIndex(j));
myCell->setLayout(m->layout());
}
@@ -50,7 +50,7 @@ bool StorageExpressionModelListController::handleEventOnExpression(Ion::Events::
}
if (event == Ion::Events::Backspace && !isAddEmptyRow(selectedRow())) {
Ion::Storage::Record record = modelStore()->recordAtIndex(modelIndexForRow(selectedRow()));
StorageExpressionModel * model = modelStore()->modelForRecord(record);
ExpiringPointer<StorageExpressionModel> model = modelStore()->modelForRecord(record);
if (model->shouldBeClearedBeforeRemove()) {
reinitExpression(model);
} else {
@@ -81,7 +81,7 @@ void StorageExpressionModelListController::addEmptyModel() {
editExpression(Ion::Events::OK);
}
void StorageExpressionModelListController::reinitExpression(StorageExpressionModel * model) {
void StorageExpressionModelListController::reinitExpression(ExpiringPointer<StorageExpressionModel> model) {
model->setContent("");
selectableTableView()->reloadData();
}
@@ -91,7 +91,7 @@ void StorageExpressionModelListController::editExpression(Ion::Events::Event eve
char initialTextContent[TextField::maxBufferSize()];
if (event == Ion::Events::OK || event == Ion::Events::EXE) {
Ion::Storage::Record record = modelStore()->recordAtIndex(modelIndexForRow(selectedRow()));
StorageExpressionModel * model = modelStore()->modelForRecord(record);
ExpiringPointer<StorageExpressionModel> model = modelStore()->modelForRecord(record);
model->text(initialTextContent, TextField::maxBufferSize());
initialText = initialTextContent;
}
@@ -108,7 +108,7 @@ void StorageExpressionModelListController::editExpression(Ion::Events::Event eve
void StorageExpressionModelListController::editSelectedRecordWithText(const char * text) {
Ion::Storage::Record record = modelStore()->recordAtIndex(modelIndexForRow(selectedRow()));
StorageExpressionModel * model = modelStore()->modelForRecord(record);
ExpiringPointer<StorageExpressionModel> model = modelStore()->modelForRecord(record);
model->setContent(text);
}

View File

@@ -20,7 +20,7 @@ protected:
bool handleEventOnExpression(Ion::Events::Event event);
virtual void addEmptyModel();
virtual void didChangeModelsList() {}
virtual void reinitExpression(StorageExpressionModel * model);
virtual void reinitExpression(ExpiringPointer<StorageExpressionModel> model);
virtual void editExpression(Ion::Events::Event event);
virtual void editSelectedRecordWithText(const char * text);
virtual bool removeModelRow(Ion::Storage::Record record);

View File

@@ -15,7 +15,7 @@ Ion::Storage::Record StorageExpressionModelStore::recordAtIndex(int i) const {
return Ion::Storage::sharedStorage()->recordWithExtensionAtIndex(modelExtension(), i);
}
StorageExpressionModel * StorageExpressionModelStore::modelForRecord(Ion::Storage::Record record) const {
StorageExpressionModel * StorageExpressionModelStore::privateModelForRecord(Ion::Storage::Record record) const {
uint32_t currentStorageChecksum = Ion::Storage::sharedStorage()->checksum();
/* If the storage changed since last call to modelForRecord, we invalid all
* memoized models. Indeed, if f(x) = A+x, and A changed, f(x) memoization
@@ -55,12 +55,12 @@ void StorageExpressionModelStore::tidy() {
int StorageExpressionModelStore::numberOfModelsSatisfyingTest(ModelTest test) const {
int result = 0;
int i = 0;
StorageExpressionModel * m = modelForRecord(recordAtIndex(i++));
StorageExpressionModel * m = privateModelForRecord(recordAtIndex(i++));
while (!m->isNull()) {
if (test(m)) {
result++;
}
m = modelForRecord(recordAtIndex(i++));
m = privateModelForRecord(recordAtIndex(i++));
}
return result;
}
@@ -70,7 +70,7 @@ Ion::Storage::Record StorageExpressionModelStore::recordStatifyingTestAtIndex(in
int index = 0;
int currentModelIndex = 0;
Ion::Storage::Record r = recordAtIndex(currentModelIndex++);
StorageExpressionModel * m = modelForRecord(r);
StorageExpressionModel * m = privateModelForRecord(r);
while (!m->isNull()) {
assert(currentModelIndex <= numberOfModels());
if (test(m)) {
@@ -80,7 +80,7 @@ Ion::Storage::Record StorageExpressionModelStore::recordStatifyingTestAtIndex(in
index++;
}
r = recordAtIndex(currentModelIndex++);
m = modelForRecord(r);
m = privateModelForRecord(r);
}
assert(false);
return Ion::Storage::Record();

View File

@@ -2,6 +2,7 @@
#define SHARED_STORAGE_EXPRESSION_MODEL_STORE_H
#include "storage_expression_model.h"
#include "expiring_pointer.h"
#include <ion/storage.h>
#include <assert.h>
@@ -19,7 +20,7 @@ public:
int numberOfDefinedModels() const { return numberOfModelsSatisfyingTest([](StorageExpressionModel * m) { return m->isDefined(); }); }
Ion::Storage::Record recordAtIndex(int i) const;
Ion::Storage::Record definedRecordAtIndex(int i) const { return recordStatifyingTestAtIndex(i, [](StorageExpressionModel * m) { return m->isDefined(); }); }
virtual StorageExpressionModel * modelForRecord(Ion::Storage::Record record) const;
ExpiringPointer<StorageExpressionModel> modelForRecord(Ion::Storage::Record record) const { return ExpiringPointer<StorageExpressionModel>(privateModelForRecord(record)); }
// Add and Remove
virtual Ion::Storage::Record::ErrorStatus addEmptyModel() = 0;
@@ -33,6 +34,7 @@ protected:
typedef bool (*ModelTest)(StorageExpressionModel * model);
int numberOfModelsSatisfyingTest(ModelTest test) const;
Ion::Storage::Record recordStatifyingTestAtIndex(int i, ModelTest test) const;
StorageExpressionModel * privateModelForRecord(Ion::Storage::Record record) const;
private:
void resetMemoizedModels() const;
virtual void setMemoizedModelAtIndex(int cacheIndex, Ion::Storage::Record) const = 0;

View File

@@ -7,7 +7,7 @@ using namespace Poincare;
namespace Shared {
void StorageFunctionBannerDelegate::reloadBannerViewForCursorOnFunction(CurveViewCursor * cursor, Ion::Storage::Record record, StorageFunctionStore * functionStore, char symbol) {
StorageFunction * function = functionStore->modelForRecord(record);
ExpiringPointer<StorageFunction> function = functionStore->modelForRecord(record);
constexpr int bufferSize = k_maxNumberOfCharacters+PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits);
char buffer[bufferSize];
const char * space = " ";

View File

@@ -23,7 +23,7 @@ double StorageFunctionGoToParameterController::parameterAtIndex(int index) {
bool StorageFunctionGoToParameterController::setParameterAtIndex(int parameterIndex, double f) {
assert(parameterIndex == 0);
StorageFunctionApp * myApp = (StorageFunctionApp *)app();
StorageFunction * function = myApp->functionStore()->modelForRecord(m_record);
ExpiringPointer<StorageFunction> function = myApp->functionStore()->modelForRecord(m_record);
float y = function->evaluateAtAbscissa(f, myApp->localContext());
if (std::fabs(f) > k_maxDisplayableFloat || std::fabs(y) > k_maxDisplayableFloat) {
app()->displayWarning(I18n::Message::ForbiddenValue);

View File

@@ -89,7 +89,7 @@ InteractiveCurveViewRangeDelegate::Range StorageFunctionGraphController::compute
return range;
}
for (int i=0; i<functionStore()->numberOfActiveFunctions(); i++) {
StorageFunction * f = functionStore()->modelForRecord(functionStore()->activeRecordAtIndex(i));
ExpiringPointer<StorageFunction> f = functionStore()->modelForRecord(functionStore()->activeRecordAtIndex(i));
float y = 0.0f;
float res = curveView()->resolution();
/* Scan x-range from the middle to the extrema in order to get balanced
@@ -125,7 +125,7 @@ void StorageFunctionGraphController::initCursorParameters() {
int functionIndex = 0;
double y = 0;
do {
StorageFunction * firstFunction = functionStore()->modelForRecord(functionStore()->activeRecordAtIndex(functionIndex++));
ExpiringPointer<StorageFunction> firstFunction = functionStore()->modelForRecord(functionStore()->activeRecordAtIndex(functionIndex++));
y = firstFunction->evaluateAtAbscissa(x, myApp->localContext());
} while ((std::isnan(y) || std::isinf(y)) && functionIndex < functionStore()->numberOfActiveFunctions());
m_cursor->moveTo(x, y);

View File

@@ -17,7 +17,7 @@ public:
int numberOfActiveFunctions() const { return numberOfModelsSatisfyingTest([](StorageExpressionModel * m) { return m->isDefined() && static_cast<StorageFunction *>(m)->isActive(); }); }
Ion::Storage::Record activeRecordAtIndex(int i) const { return recordStatifyingTestAtIndex(i, [](StorageExpressionModel * m) { return m->isDefined() && static_cast<StorageFunction *>(m)->isActive(); }); }
StorageFunction * modelForRecord(Ion::Storage::Record record) const override { return static_cast<StorageFunction *>(StorageExpressionModelStore::modelForRecord(record)); }
ExpiringPointer<StorageFunction> modelForRecord(Ion::Storage::Record record) const { return ExpiringPointer<StorageFunction>(static_cast<StorageFunction *>(privateModelForRecord(record))); }
virtual char symbol() const = 0;
};

View File

@@ -94,7 +94,7 @@ bool StorageListParameterController::handleEnterOnRow(int rowIndex) {
}
}
StorageFunction * StorageListParameterController::function() {
ExpiringPointer<StorageFunction> StorageListParameterController::function() {
return functionStore()->modelForRecord(m_record);
}

View File

@@ -34,7 +34,7 @@ protected:
SelectableTableView m_selectableTableView;
Ion::Storage::Record m_record;
private:
StorageFunction * function();
ExpiringPointer<StorageFunction> function();
StorageFunctionStore * functionStore();
#if FUNCTION_COLOR_CHOICE
MessageTableCellWithChevron m_colorCell;

View File

@@ -103,7 +103,7 @@ bool StorageSumGraphController::handleEvent(Ion::Events::Event event) {
bool StorageSumGraphController::moveCursorHorizontallyToPosition(double x) {
StorageFunctionApp * myApp = static_cast<StorageFunctionApp *>(app());
assert(!m_record.isNull());
StorageFunction * function = myApp->functionStore()->modelForRecord(m_record);
ExpiringPointer<StorageFunction> function = myApp->functionStore()->modelForRecord(m_record);
double y = function->evaluateAtAbscissa(x, myApp->localContext());
m_cursor->moveTo(x, y);
if (m_step == Step::FirstParameter) {
@@ -191,7 +191,7 @@ bool StorageSumGraphController::handleEnter() {
m_step = (Step)((int)m_step+1);
StorageFunctionApp * myApp = static_cast<StorageFunctionApp *>(app());
assert(!m_record.isNull());
StorageFunction * function = myApp->functionStore()->modelForRecord(m_record);
ExpiringPointer<StorageFunction> function = myApp->functionStore()->modelForRecord(m_record);
double sum = function->sumBetweenBounds(m_startSum, m_endSum, myApp->localContext());
m_legendView.setSumSymbol(m_step, m_startSum, m_endSum, sum, createFunctionLayout(function));
m_legendView.setLegendMessage(I18n::Message::Default, m_step);

View File

@@ -9,6 +9,7 @@
#include "simple_interactive_curve_view_controller.h"
#include "storage_function.h"
#include "text_field_delegate.h"
#include "expiring_pointer.h"
namespace Shared {
@@ -39,7 +40,7 @@ private:
constexpr static float k_cursorBottomMarginRatio = 0.28f; // (cursorHeight/2+bannerHeigh)/graphViewHeight
virtual I18n::Message legendMessageAtStep(Step step) = 0;
virtual double cursorNextStep(double position, int direction) = 0;
virtual Poincare::Layout createFunctionLayout(StorageFunction * function) = 0;
virtual Poincare::Layout createFunctionLayout(ExpiringPointer<StorageFunction> function) = 0;
Shared::InteractiveCurveViewRange * interactiveCurveViewRange() override { return m_graphRange; }
Shared::CurveView * curveView() override { return m_graphView; }
TextFieldDelegateApp * textFieldDelegateApp() override {

View File

@@ -309,7 +309,7 @@ int StorageValuesController::maxNumberOfElements() const {
}
double StorageValuesController::evaluationOfAbscissaAtColumn(double abscissa, int columnIndex) {
StorageFunction * function = functionStore()->modelForRecord(recordAtColumn(columnIndex));
ExpiringPointer<StorageFunction> function = functionStore()->modelForRecord(recordAtColumn(columnIndex));
TextFieldDelegateApp * myApp = (TextFieldDelegateApp *)app();
return function->evaluateAtAbscissa(abscissa, myApp->localContext());
}