Merged PR 10790341: [Recall] Update calculator engine with snapshot for further calculations

####What
When restoring from snapshot, we need to set calculator engine properly to make further calculations correct.

####How
Update calculator engine by a serial of corresponding commands from snapshot.

To get the commands for the display area when saving snapshot,
1. If the expression is not from history and the primary display is the result of the expression, `DisplayCommands` of `StandardCalculatorSnapshot` will be empty, and we will use the commands from `ExpressionDisplay` for restoring in the future.
2. If the expression is not from history and the primary display is not the result of the expression, `DisplayCommands` of `StandardCalculatorSnapshot` will be the commands from the history collector in addition to the operand command in the primary display, and it will be used for restoring in the future.
3. If the expression and primary display are from history, `DisplayCommands` will be incomplete with the operand command in the primary display missing as by current design of history, and the commands from `ExpressionDisplay` will be used for restoring in the future.

Related work items: #51002745
This commit is contained in:
Han Zhang 👾 2024-05-21 07:22:32 +00:00
commit 089f7deb08
9 changed files with 161 additions and 96 deletions

View file

@ -3,7 +3,6 @@
#include "Header Files/CalcEngine.h" #include "Header Files/CalcEngine.h"
#include "Command.h" #include "Command.h"
#include "ExpressionCommand.h"
#include "winerror_cross_platform.h" #include "winerror_cross_platform.h"
constexpr int ASCII_0 = 48; constexpr int ASCII_0 = 48;
@ -66,47 +65,7 @@ CHistoryCollector::~CHistoryCollector()
void CHistoryCollector::AddOpndToHistory(wstring_view numStr, Rational const& rat, bool fRepetition) void CHistoryCollector::AddOpndToHistory(wstring_view numStr, Rational const& rat, bool fRepetition)
{ {
std::shared_ptr<std::vector<int>> commands = std::make_shared<vector<int>>(); int iCommandEnd = AddCommand(GetOperandCommandsFromString(numStr, rat));
// Check for negate
bool fNegative = (numStr[0] == L'-');
bool fSciFmt = false;
bool fDecimal = false;
for (size_t i = (fNegative ? 1 : 0); i < numStr.length(); i++)
{
if (numStr[i] == m_decimalSymbol)
{
commands->push_back(IDC_PNT);
if (!fSciFmt)
{
fDecimal = true;
}
}
else if (numStr[i] == L'e')
{
commands->push_back(IDC_EXP);
fSciFmt = true;
}
else if (numStr[i] == L'-')
{
commands->push_back(IDC_SIGN);
}
else if (numStr[i] == L'+')
{
// Ignore.
}
// Number
else
{
int num = static_cast<int>(numStr[i]) - ASCII_0;
num += IDC_0;
commands->push_back(num);
}
}
auto operandCommand = std::make_shared<COpndCommand>(commands, fNegative, fDecimal, fSciFmt);
operandCommand->Initialize(rat);
int iCommandEnd = AddCommand(operandCommand);
m_lastOpStartIndex = IchAddSzToEquationSz(numStr, iCommandEnd); m_lastOpStartIndex = IchAddSzToEquationSz(numStr, iCommandEnd);
if (fRepetition) if (fRepetition)
@ -201,7 +160,7 @@ void CHistoryCollector::EnclosePrecInversionBrackets()
IchAddSzToEquationSz(CCalcEngine::OpCodeToString(IDC_CLOSEP), -1); IchAddSzToEquationSz(CCalcEngine::OpCodeToString(IDC_CLOSEP), -1);
} }
bool CHistoryCollector::FOpndAddedToHistory() bool CHistoryCollector::FOpndAddedToHistory() const
{ {
return (-1 != m_lastOpStartIndex); return (-1 != m_lastOpStartIndex);
} }
@ -465,7 +424,7 @@ void CHistoryCollector::SetDecimalSymbol(wchar_t decimalSymbol)
} }
// Update the commands corresponding to the passed string Number // Update the commands corresponding to the passed string Number
std::shared_ptr<std::vector<int>> CHistoryCollector::GetOperandCommandsFromString(wstring_view numStr) std::shared_ptr<std::vector<int>> CHistoryCollector::GetOperandCommandsFromString(wstring_view numStr) const
{ {
std::shared_ptr<std::vector<int>> commands = std::make_shared<std::vector<int>>(); std::shared_ptr<std::vector<int>> commands = std::make_shared<std::vector<int>>();
// Check for negate // Check for negate
@ -505,3 +464,58 @@ std::shared_ptr<std::vector<int>> CHistoryCollector::GetOperandCommandsFromStrin
} }
return commands; return commands;
} }
std::shared_ptr<COpndCommand> CHistoryCollector::GetOperandCommandsFromString(std::wstring_view numStr, Rational const& rat) const
{
std::shared_ptr<std::vector<int>> commands = std::make_shared<vector<int>>();
// Check for negate
bool fNegative = (numStr[0] == L'-');
bool fSciFmt = false;
bool fDecimal = false;
for (size_t i = (fNegative ? 1 : 0); i < numStr.length(); i++)
{
if (numStr[i] == m_decimalSymbol)
{
commands->push_back(IDC_PNT);
if (!fSciFmt)
{
fDecimal = true;
}
}
else if (numStr[i] == L'e')
{
commands->push_back(IDC_EXP);
fSciFmt = true;
}
else if (numStr[i] == L'-')
{
commands->push_back(IDC_SIGN);
}
else if (numStr[i] == L'+')
{
// Ignore.
}
// Number
else
{
int num = static_cast<int>(numStr[i]) - ASCII_0;
num += IDC_0;
commands->push_back(num);
}
}
auto operandCommand = std::make_shared<COpndCommand>(commands, fNegative, fDecimal, fSciFmt);
operandCommand->Initialize(rat);
return operandCommand;
}
std::vector<std::shared_ptr<IExpressionCommand>> CHistoryCollector::GetCommands() const
{
std::vector<std::shared_ptr<IExpressionCommand>> commands;
if (m_spCommands != nullptr)
{
commands = *m_spCommands;
}
return commands;
}

View file

@ -202,3 +202,13 @@ wchar_t CCalcEngine::DecimalSeparator() const
{ {
return m_decimalSeparator; return m_decimalSeparator;
} }
std::vector<std::shared_ptr<IExpressionCommand>> CCalcEngine::GetHistoryCollectorCommandsSnapshot() const
{
auto commands = m_HistoryCollector.GetCommands();
if (!m_HistoryCollector.FOpndAddedToHistory() && m_bRecord)
{
commands.push_back(m_HistoryCollector.GetOperandCommandsFromString(m_numberString, m_currentVal));
}
return commands;
}

View file

@ -597,4 +597,9 @@ namespace CalculationManager
{ {
m_inHistoryItemLoadMode = isHistoryItemLoadMode; m_inHistoryItemLoadMode = isHistoryItemLoadMode;
} }
std::vector<std::shared_ptr<IExpressionCommand>> CalculatorManager::GetDisplayCommandsSnapshot() const
{
return m_currentCalculatorEngine->GetHistoryCollectorCommandsSnapshot();
}
} }

View file

@ -119,5 +119,6 @@ namespace CalculationManager
} }
CalculationManager::Command GetCurrentDegreeMode(); CalculationManager::Command GetCurrentDegreeMode();
void SetInHistoryItemLoadMode(_In_ bool isHistoryItemLoadMode); void SetInHistoryItemLoadMode(_In_ bool isHistoryItemLoadMode);
std::vector<std::shared_ptr<IExpressionCommand>> GetDisplayCommandsSnapshot() const;
}; };
} }

View file

@ -89,6 +89,8 @@ public:
void UpdateMaxIntDigits(); void UpdateMaxIntDigits();
wchar_t DecimalSeparator() const; wchar_t DecimalSeparator() const;
std::vector<std::shared_ptr<IExpressionCommand>> GetHistoryCollectorCommandsSnapshot() const;
// Static methods for the instance // Static methods for the instance
static void static void
InitialOneTimeOnlySetup(CalculationManager::IResourceProvider& resourceProvider); // Once per load time to call to initialize all shared global variables InitialOneTimeOnlySetup(CalculationManager::IResourceProvider& resourceProvider); // Once per load time to call to initialize all shared global variables

View file

@ -4,10 +4,13 @@
#pragma once #pragma once
#include <array> #include <array>
#include "ExpressionCommand.h"
#include "ICalcDisplay.h" #include "ICalcDisplay.h"
#include "IHistoryDisplay.h" #include "IHistoryDisplay.h"
#include "Rational.h" #include "Rational.h"
class COpndCommand;
// maximum depth you can get by precedence. It is just an array's size limit. // maximum depth you can get by precedence. It is just an array's size limit.
static constexpr size_t MAXPRECDEPTH = 25; static constexpr size_t MAXPRECDEPTH = 25;
@ -29,13 +32,15 @@ public:
void PushLastOpndStart(int ichOpndStart = -1); void PushLastOpndStart(int ichOpndStart = -1);
void PopLastOpndStart(); void PopLastOpndStart();
void EnclosePrecInversionBrackets(); void EnclosePrecInversionBrackets();
bool FOpndAddedToHistory(); bool FOpndAddedToHistory() const;
void CompleteHistoryLine(std::wstring_view numStr); void CompleteHistoryLine(std::wstring_view numStr);
void CompleteEquation(std::wstring_view numStr); void CompleteEquation(std::wstring_view numStr);
void ClearHistoryLine(std::wstring_view errStr); void ClearHistoryLine(std::wstring_view errStr);
int AddCommand(_In_ const std::shared_ptr<IExpressionCommand>& spCommand); int AddCommand(_In_ const std::shared_ptr<IExpressionCommand>& spCommand);
void UpdateHistoryExpression(uint32_t radix, int32_t precision); void UpdateHistoryExpression(uint32_t radix, int32_t precision);
void SetDecimalSymbol(wchar_t decimalSymbol); void SetDecimalSymbol(wchar_t decimalSymbol);
std::shared_ptr<COpndCommand> GetOperandCommandsFromString(std::wstring_view numStr, CalcEngine::Rational const& rat) const;
std::vector<std::shared_ptr<IExpressionCommand>> GetCommands() const;
private: private:
std::shared_ptr<IHistoryDisplay> m_pHistoryDisplay; std::shared_ptr<IHistoryDisplay> m_pHistoryDisplay;
@ -60,5 +65,5 @@ private:
void TruncateEquationSzFromIch(int ich); void TruncateEquationSzFromIch(int ich);
void SetExpressionDisplay(); void SetExpressionDisplay();
void InsertSzInEquationSz(std::wstring_view str, int icommandIndex, int ich); void InsertSzInEquationSz(std::wstring_view str, int icommandIndex, int ich);
std::shared_ptr<std::vector<int>> GetOperandCommandsFromString(std::wstring_view numStr); std::shared_ptr<std::vector<int>> GetOperandCommandsFromString(std::wstring_view numStr) const;
}; };

View file

@ -63,6 +63,12 @@ namespace
{ {
jsonObject->SetNamedValue(L"ExpressionDisplay", SaveSnapshotToJson(*value.ExpressionDisplay)); jsonObject->SetNamedValue(L"ExpressionDisplay", SaveSnapshotToJson(*value.ExpressionDisplay));
} }
auto commandsJsonArray = ref new Windows::Data::Json::JsonArray();
for (const auto& command : value.DisplayCommands)
{
commandsJsonArray->Append(SaveSnapshotToJson(command));
}
jsonObject->SetNamedValue(L"DisplayCommands", commandsJsonArray);
return jsonObject; return jsonObject;
} }
@ -270,6 +276,7 @@ namespace
return; return;
} }
} }
standardCalculatorSnapshot.DisplayCommands = RestoreExpressionCommandsFromJsonArray(jsonObject->GetNamedArray(L"DisplayCommands"));
value = std::move(standardCalculatorSnapshot); value = std::move(standardCalculatorSnapshot);
} }

View file

@ -42,6 +42,57 @@ namespace
StringReference IsBitFlipCheckedPropertyName(L"IsBitFlipChecked"); StringReference IsBitFlipCheckedPropertyName(L"IsBitFlipChecked");
StringReference CalcAlwaysOnTop(L"CalcAlwaysOnTop"); StringReference CalcAlwaysOnTop(L"CalcAlwaysOnTop");
StringReference CalcBackToFullView(L"CalcBackToFullView"); StringReference CalcBackToFullView(L"CalcBackToFullView");
std::vector<int> GetCommandsFromExpressionCommands(const std::vector<std::shared_ptr<IExpressionCommand>>& expressionCommands)
{
vector<int> commands;
for (const auto& command : expressionCommands)
{
CommandType commandType = command->GetCommandType();
if (commandType == CommandType::UnaryCommand)
{
shared_ptr<IUnaryCommand> spCommand = dynamic_pointer_cast<IUnaryCommand>(command);
const shared_ptr<vector<int>>& unaryCommands = spCommand->GetCommands();
for (int nUCode : *unaryCommands)
{
commands.push_back(nUCode);
}
}
if (commandType == CommandType::BinaryCommand)
{
shared_ptr<IBinaryCommand> spCommand = dynamic_pointer_cast<IBinaryCommand>(command);
commands.push_back(spCommand->GetCommand());
}
if (commandType == CommandType::Parentheses)
{
shared_ptr<IParenthesisCommand> spCommand = dynamic_pointer_cast<IParenthesisCommand>(command);
commands.push_back(spCommand->GetCommand());
}
if (commandType == CommandType::OperandCommand)
{
shared_ptr<IOpndCommand> spCommand = dynamic_pointer_cast<IOpndCommand>(command);
const shared_ptr<vector<int>>& opndCommands = spCommand->GetCommands();
bool fNeedIDCSign = spCommand->IsNegative();
for (int nOCode : *opndCommands)
{
commands.push_back(nOCode);
if (fNeedIDCSign && nOCode != IDC_0)
{
commands.push_back(static_cast<int>(CalculationManager::Command::CommandSIGN));
fNeedIDCSign = false;
}
}
}
}
return commands;
}
} }
namespace CalculatorResourceKeys namespace CalculatorResourceKeys
@ -1388,55 +1439,8 @@ void StandardCalculatorViewModel::Recalculate(bool fromHistory)
{ {
// Recalculate // Recalculate
Command currentDegreeMode = m_standardCalculatorManager.GetCurrentDegreeMode(); Command currentDegreeMode = m_standardCalculatorManager.GetCurrentDegreeMode();
shared_ptr<vector<shared_ptr<IExpressionCommand>>> savedCommands = make_shared<vector<shared_ptr<IExpressionCommand>>>(); shared_ptr<vector<shared_ptr<IExpressionCommand>>> savedCommands = std::make_shared<std::vector<shared_ptr<IExpressionCommand>>>(*m_commands);
vector<int> currentCommands; vector<int> currentCommands = GetCommandsFromExpressionCommands(*m_commands);
for (const auto& command : *m_commands)
{
savedCommands->push_back(command);
CommandType commandType = command->GetCommandType();
if (commandType == CommandType::UnaryCommand)
{
shared_ptr<IUnaryCommand> spCommand = dynamic_pointer_cast<IUnaryCommand>(command);
const shared_ptr<vector<int>>& unaryCommands = spCommand->GetCommands();
for (int nUCode : *unaryCommands)
{
currentCommands.push_back(nUCode);
}
}
if (commandType == CommandType::BinaryCommand)
{
shared_ptr<IBinaryCommand> spCommand = dynamic_pointer_cast<IBinaryCommand>(command);
currentCommands.push_back(spCommand->GetCommand());
}
if (commandType == CommandType::Parentheses)
{
shared_ptr<IParenthesisCommand> spCommand = dynamic_pointer_cast<IParenthesisCommand>(command);
currentCommands.push_back(spCommand->GetCommand());
}
if (commandType == CommandType::OperandCommand)
{
shared_ptr<IOpndCommand> spCommand = dynamic_pointer_cast<IOpndCommand>(command);
const shared_ptr<vector<int>>& opndCommands = spCommand->GetCommands();
bool fNeedIDCSign = spCommand->IsNegative();
for (int nOCode : *opndCommands)
{
currentCommands.push_back(nOCode);
if (fNeedIDCSign && nOCode != IDC_0)
{
currentCommands.push_back(static_cast<int>(CalculationManager::Command::CommandSIGN));
fNeedIDCSign = false;
}
}
}
}
shared_ptr<vector<pair<wstring, int>>> savedTokens = make_shared<vector<pair<wstring, int>>>(); shared_ptr<vector<pair<wstring, int>>> savedTokens = make_shared<vector<pair<wstring, int>>>();
@ -1796,6 +1800,7 @@ StandardCalculatorSnapshot StandardCalculatorViewModel::GetStandardCalculatorSna
{ {
snapshot.ExpressionDisplay = { *m_tokens, *m_commands }; snapshot.ExpressionDisplay = { *m_tokens, *m_commands };
} }
snapshot.DisplayCommands = m_standardCalculatorManager.GetDisplayCommandsSnapshot();
return snapshot; return snapshot;
} }
@ -1805,11 +1810,26 @@ void StandardCalculatorViewModel::SetStandardCalculatorSnapshot(const StandardCa
{ {
m_standardCalculatorManager.SetHistoryItems(snapshot.CalcManager.HistoryItems.value()); m_standardCalculatorManager.SetHistoryItems(snapshot.CalcManager.HistoryItems.value());
} }
SetPrimaryDisplay(snapshot.PrimaryDisplay.DisplayValue, snapshot.PrimaryDisplay.IsError);
std::vector<int> commands;
if (snapshot.ExpressionDisplay.has_value() && snapshot.ExpressionDisplay->Tokens.back().first == L"=")
{
commands = GetCommandsFromExpressionCommands(snapshot.ExpressionDisplay->Commands);
}
if (commands.empty() && !snapshot.DisplayCommands.empty())
{
commands = GetCommandsFromExpressionCommands(snapshot.DisplayCommands);
}
for (const auto& command : commands)
{
m_standardCalculatorManager.SendCommand(static_cast<Command>(command));
}
if (snapshot.ExpressionDisplay.has_value()) if (snapshot.ExpressionDisplay.has_value())
{ {
SetExpressionDisplay( SetExpressionDisplay(
std::make_shared<std::vector<std::pair<std::wstring, int>>>(snapshot.ExpressionDisplay->Tokens), std::make_shared<std::vector<std::pair<std::wstring, int>>>(snapshot.ExpressionDisplay->Tokens),
std::make_shared<std::vector<std::shared_ptr<IExpressionCommand>>>(snapshot.ExpressionDisplay->Commands)); std::make_shared<std::vector<std::shared_ptr<IExpressionCommand>>>(snapshot.ExpressionDisplay->Commands));
} }
SetPrimaryDisplay(snapshot.PrimaryDisplay.DisplayValue, snapshot.PrimaryDisplay.IsError);
} }

View file

@ -55,6 +55,7 @@ namespace CalculatorApp
CalculatorManagerSnapshot CalcManager; CalculatorManagerSnapshot CalcManager;
PrimaryDisplaySnapshot PrimaryDisplay; PrimaryDisplaySnapshot PrimaryDisplay;
std::optional<ExpressionDisplaySnapshot> ExpressionDisplay; std::optional<ExpressionDisplaySnapshot> ExpressionDisplay;
std::vector<std::shared_ptr<IExpressionCommand>> DisplayCommands;
}; };
[Windows::UI::Xaml::Data::Bindable] public ref class StandardCalculatorViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged [Windows::UI::Xaml::Data::Bindable] public ref class StandardCalculatorViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged