mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-19 05:40:38 +01:00
[shared] Create ExpiringPointer: in DEBUG, check that pointers to
memoized functions are not used when invalid
This commit is contained in:
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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 = " ";
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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\
|
||||
|
||||
17
apps/shared/expiring_pointer.cpp
Normal file
17
apps/shared/expiring_pointer.cpp
Normal 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
|
||||
|
||||
}
|
||||
37
apps/shared/expiring_pointer.h
Normal file
37
apps/shared/expiring_pointer.h
Normal 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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 = " ";
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -94,7 +94,7 @@ bool StorageListParameterController::handleEnterOnRow(int rowIndex) {
|
||||
}
|
||||
}
|
||||
|
||||
StorageFunction * StorageListParameterController::function() {
|
||||
ExpiringPointer<StorageFunction> StorageListParameterController::function() {
|
||||
return functionStore()->modelForRecord(m_record);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user