Files
Upsilon/apps/calculation/calculation_store.h

81 lines
3.3 KiB
C++

#ifndef CALCULATION_CALCULATION_STORE_H
#define CALCULATION_CALCULATION_STORE_H
#include "calculation.h"
#include <apps/shared/expiring_pointer.h>
namespace Calculation {
/* To optimize the storage space, we use one big buffer for all calculations.
*
* The previous solution was to keep 10 calculations, each containing 3 buffers
* (for input and outputs). To optimize the storage, we then wanted to put all
* outputs in a cache where they could be deleted to add a new entry, and
* recomputed on cache miss. However, the computation depends too much on the
* state of the memory for this to be possible. For instance:
* 6->a
* a+1
* Perform some big computations that remove a+1 from the cache
* Delete a from the variable box.
* Scroll up to display a+1 : a does not exist anymore so the outputs won't be
* recomputed correctly.
*
* Now we do not cap the number of calculations and just delete the oldests to
* create space for a new calculation. */
class CalculationStore {
public:
CalculationStore();
Shared::ExpiringPointer<Calculation> calculationAtIndex(int i);
Shared::ExpiringPointer<Calculation> push(const char * text, Poincare::Context * context);
void deleteCalculationAtIndex(int i);
void deleteAll();
int numberOfCalculations() const { return m_numberOfCalculations; }
Poincare::Expression ansExpression(Poincare::Context * context);
void tidy();
private:
static constexpr int k_maxNumberOfCalculations = 25;
static constexpr int k_bufferSize = 10 * 3 * Constant::MaxSerializedExpressionSize;
class CalculationIterator {
public:
CalculationIterator(const char * c) : m_calculation(reinterpret_cast<Calculation *>(const_cast<char *>(c))) {}
Calculation * operator*() { return m_calculation; }
bool operator!=(const CalculationIterator& it) const { return (m_calculation != it.m_calculation); }
CalculationIterator & operator++() {
m_calculation = m_calculation->next();
return *this;
}
protected:
Calculation * m_calculation;
};
CalculationIterator begin() const { return CalculationIterator(m_buffer); }
CalculationIterator end() const { return CalculationIterator(m_bufferEnd); }
Calculation * bufferCalculationAtIndex(int i);
int remainingBufferSize() const { assert(m_bufferEnd >= m_buffer); return k_bufferSize - (m_bufferEnd - m_buffer); }
bool serializeExpression(Poincare::Expression e, char * location, char * * newCalculationsLocation);
char * slideCalculationsToEndOfBuffer(); // returns the new position of the calculations
size_t deleteLastCalculation(const char * calculationsStart = nullptr);
const char * lastCalculationPosition(const char * calculationsStart) const;
typedef bool (*ValueCreator)(char * location, size_t locationSize, void * e);
bool pushExpression(ValueCreator valueCrator, Poincare::Expression * expression, char * location, char * * newCalculationsLocation);
Shared::ExpiringPointer<Calculation> emptyStoreAndPushUndef(Poincare::Context * context);
char m_buffer[k_bufferSize];
const char * m_bufferEnd;
int m_numberOfCalculations;
bool m_slidedBuffer;
// Memoization
static constexpr int k_numberOfMemoizedCalculationPointers = 10;
void resetMemoizedModelsAfterCalculationIndex(int index);
int m_indexOfFirstMemoizedCalculationPointer;
mutable Calculation * m_memoizedCalculationPointers[k_numberOfMemoizedCalculationPointers];
};
}
#endif