diff --git a/apps/calculation/app.cpp b/apps/calculation/app.cpp index 7dd1646e9..5cb19d37d 100644 --- a/apps/calculation/app.cpp +++ b/apps/calculation/app.cpp @@ -35,6 +35,7 @@ App::Descriptor * App::Snapshot::descriptor() { } void App::Snapshot::tidy() { + m_calculationStore.tidy(); } App::App(Snapshot * snapshot) : diff --git a/apps/calculation/calculation_store.cpp b/apps/calculation/calculation_store.cpp index 3f4fa58e0..c8b990129 100644 --- a/apps/calculation/calculation_store.cpp +++ b/apps/calculation/calculation_store.cpp @@ -9,18 +9,43 @@ using namespace Shared; namespace Calculation { +CalculationStore::CalculationStore() : + m_bufferEnd(m_buffer), + m_numberOfCalculations(0), + m_slidedBuffer(false), + m_indexOfFirstMemoizedCalculationPointer(0) +{ + resetMemoizedModelsAfterCalculationIndex(-1); +} + ExpiringPointer CalculationStore::calculationAtIndex(int i) { assert(!m_slidedBuffer); assert(i >= 0 && i < m_numberOfCalculations); - int currentIndex = 0; - for (Calculation * c : *this) { - if (currentIndex == i) { + assert(m_indexOfFirstMemoizedCalculationPointer >= 0); + if (i >= m_indexOfFirstMemoizedCalculationPointer && i < m_indexOfFirstMemoizedCalculationPointer + k_numberOfMemoizedCalculationPointers) { + // The calculation is within the range of memoized calculations + Calculation * c = m_memoizedCalculationPointers[i]; + if (c != nullptr) { + // The pointer was memoized return ExpiringPointer(c); } - currentIndex++; + c = bufferCalculationAtIndex(i); + m_memoizedCalculationPointers[i] = c; + return c; } - assert(false); - return nullptr; + // Slide the memoization buffer + if (i >= m_indexOfFirstMemoizedCalculationPointer) { + // Slide the memoization buffer to the left + memcpy(m_memoizedCalculationPointers, m_memoizedCalculationPointers+1, k_numberOfMemoizedCalculationPointers - 1 * sizeof(Calculation *)); + m_memoizedCalculationPointers[k_numberOfMemoizedCalculationPointers - 1] = nullptr; + m_indexOfFirstMemoizedCalculationPointer++; + } else { + // Slide the memoization buffer to the right + memcpy(m_memoizedCalculationPointers+1, m_memoizedCalculationPointers, k_numberOfMemoizedCalculationPointers - 1 * sizeof(Calculation *)); + m_memoizedCalculationPointers[0] = nullptr; + m_indexOfFirstMemoizedCalculationPointer--; + } + return calculationAtIndex(0); } ExpiringPointer CalculationStore::push(const char * text, Context * context) { @@ -66,6 +91,10 @@ ExpiringPointer CalculationStore::push(const char * text, Context * m_slidedBuffer = false; m_numberOfCalculations++; m_bufferEnd+= nextSerializationLocation - m_buffer; + + // Clean the memoization + resetMemoizedModelsAfterCalculationIndex(-1); + return ExpiringPointer(reinterpret_cast(m_buffer)); } @@ -79,12 +108,14 @@ void CalculationStore::deleteCalculationAtIndex(int i) { memcpy((char *)(calcI.pointer()), nextCalc, slidingSize); m_bufferEnd -= (nextCalc - (char *)(calcI.pointer())); m_numberOfCalculations--; + resetMemoizedModelsAfterCalculationIndex(i); } void CalculationStore::deleteAll() { assert(!m_slidedBuffer); m_bufferEnd = m_buffer; m_numberOfCalculations = 0; + resetMemoizedModelsAfterCalculationIndex(-1); } Expression CalculationStore::ansExpression(Context * context) { @@ -106,6 +137,18 @@ Expression CalculationStore::ansExpression(Context * context) { return mostRecentCalculation->exactOutput(); } +Calculation * CalculationStore::bufferCalculationAtIndex(int i) { + int currentIndex = 0; + for (Calculation * c : *this) { + if (currentIndex == i) { + return c; + } + currentIndex++; + } + assert(false); + return nullptr; +} + void CalculationStore::serializeExpression(Expression e, char * location, char * * newCalculationsLocation) { assert(m_slidedBuffer); pushExpression( @@ -140,6 +183,7 @@ size_t CalculationStore::deleteLastCalculation(const char * calculationsStart) { memcpy(const_cast(calculationsStart + result), calculationsStart, m_buffer + k_bufferSize - calculationsStart - result); } m_numberOfCalculations--; + resetMemoizedModelsAfterCalculationIndex(-1); return result; } @@ -167,4 +211,17 @@ void CalculationStore::pushExpression(ValueCreator valueCreator, Expression * ex } } +void CalculationStore::resetMemoizedModelsAfterCalculationIndex(int index) { + if (index < m_indexOfFirstMemoizedCalculationPointer) { + memset(&m_memoizedCalculationPointers, 0, k_numberOfMemoizedCalculationPointers * sizeof(Calculation *)); + return; + } + if (index >= m_indexOfFirstMemoizedCalculationPointer + k_numberOfMemoizedCalculationPointers) { + return; + } + for (int i = index - m_indexOfFirstMemoizedCalculationPointer; i < k_numberOfMemoizedCalculationPointers; i++) { + m_memoizedCalculationPointers[i] = nullptr; + } +} + } diff --git a/apps/calculation/calculation_store.h b/apps/calculation/calculation_store.h index 1fdbcef71..224ab0c86 100644 --- a/apps/calculation/calculation_store.h +++ b/apps/calculation/calculation_store.h @@ -25,13 +25,14 @@ namespace Calculation { class CalculationStore { public: - CalculationStore() : m_bufferEnd(m_buffer), m_numberOfCalculations(0), m_slidedBuffer(false) {} + CalculationStore(); Shared::ExpiringPointer calculationAtIndex(int i); Shared::ExpiringPointer 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() { resetMemoizedModelsAfterCalculationIndex(-1); } private: static constexpr int k_bufferSize = 10 * 3 * Constant::MaxSerializedExpressionSize; @@ -51,6 +52,7 @@ private: 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); } void serializeExpression(Poincare::Expression e, char * location, char * * newCalculationsLocation); char * slideCalculationsToEndOfBuffer(); // returns the new position of the calculations @@ -62,6 +64,12 @@ private: 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]; }; }