forked from microsoft/calculator
-
Notifications
You must be signed in to change notification settings - Fork 0
/
CalcEngine.h
206 lines (181 loc) · 8.83 KB
/
CalcEngine.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
/****************************Module*Header***********************************\
* Module Name: CalcEngine.h
*
* Module Description:
* The class definition for the Calculator's engine class CCalcEngine
*
* Warnings:
*
* Created: 17-Jan-2008
*
\****************************************************************************/
#include <random>
#include "CCommand.h"
#include "EngineStrings.h"
#include "../Command.h"
#include "../ExpressionCommand.h"
#include "RadixType.h"
#include "History.h" // for History Collector
#include "CalcInput.h"
#include "CalcUtils.h"
#include "ICalcDisplay.h"
#include "Rational.h"
#include "RationalMath.h"
// The following are NOT real exports of CalcEngine, but for forward declarations
// The real exports follows later
// This is expected to be in same order as IDM_QWORD, IDM_DWORD etc.
enum eNUM_WIDTH
{
QWORD_WIDTH, // Number width of 64 bits mode (default)
DWORD_WIDTH, // Number width of 32 bits mode
WORD_WIDTH, // Number width of 16 bits mode
BYTE_WIDTH // Number width of 16 bits mode
};
typedef enum eNUM_WIDTH NUM_WIDTH;
static constexpr size_t NUM_WIDTH_LENGTH = 4;
namespace CalculationManager
{
class IResourceProvider;
}
namespace CalculatorEngineTests
{
class CalcEngineTests;
}
class CCalcEngine
{
public:
CCalcEngine(
bool fPrecedence,
bool fIntegerMode,
CalculationManager::IResourceProvider* const pResourceProvider,
__in_opt ICalcDisplay* pCalcDisplay,
__in_opt std::shared_ptr<IHistoryDisplay> pHistoryDisplay);
void ProcessCommand(OpCode wID);
void DisplayError(uint32_t nError);
std::unique_ptr<CalcEngine::Rational> PersistedMemObject();
void PersistedMemObject(CalcEngine::Rational const& memObject);
bool FInErrorState()
{
return m_bError;
}
bool IsInputEmpty()
{
return m_input.IsEmpty() && (m_numberString.empty() || m_numberString == L"0");
}
bool FInRecordingState()
{
return m_bRecord;
}
void SettingsChanged();
bool IsCurrentTooBigForTrig();
int GetCurrentRadix();
std::wstring GetCurrentResultForRadix(uint32_t radix, int32_t precision, bool groupDigitsPerRadix);
void ChangePrecision(int32_t precision)
{
m_precision = precision;
ChangeConstants(m_radix, precision);
}
std::wstring GroupDigitsPerRadix(std::wstring_view numberString, uint32_t radix);
std::wstring GetStringForDisplay(CalcEngine::Rational const& rat, uint32_t radix);
void UpdateMaxIntDigits();
wchar_t DecimalSeparator() const;
// Static methods for the instance
static void
InitialOneTimeOnlySetup(CalculationManager::IResourceProvider& resourceProvider); // Once per load time to call to initialize all shared global variables
// returns the ptr to string representing the operator. Mostly same as the button, but few special cases for x^y etc.
static std::wstring_view GetString(int ids)
{
return s_engineStrings[std::to_wstring(ids)];
}
static std::wstring_view GetString(std::wstring_view ids)
{
return s_engineStrings[ids];
}
static std::wstring_view OpCodeToString(int nOpCode)
{
return GetString(IdStrFromCmdId(nOpCode));
}
static std::wstring_view OpCodeToUnaryString(int nOpCode, bool fInv, ANGLE_TYPE angletype);
static std::wstring_view OpCodeToBinaryString(int nOpCode, bool isIntegerMode);
private:
bool m_fPrecedence;
bool m_fIntegerMode; /* This is true if engine is explicitly called to be in integer mode. All bases are restricted to be in integers only */
ICalcDisplay* m_pCalcDisplay;
CalculationManager::IResourceProvider* const m_resourceProvider;
int m_nOpCode; /* ID value of operation. */
int m_nPrevOpCode; // opcode which computed the number in m_currentVal. 0 if it is already bracketed or plain number or
// if it hasn't yet been computed
bool m_bChangeOp; /* Flag for changing operation. */
bool m_bRecord; // Global mode: recording or displaying
bool m_bSetCalcState; // Flag for setting the engine result state
CalcEngine::CalcInput m_input; // Global calc input object for decimal strings
eNUMOBJ_FMT m_nFE; /* Scientific notation conversion flag. */
CalcEngine::Rational m_maxTrigonometricNum;
std::unique_ptr<CalcEngine::Rational> m_memoryValue; // Current memory value.
CalcEngine::Rational m_holdVal; // For holding the second operand in repetitive calculations ( pressing "=" continuously)
CalcEngine::Rational m_currentVal; // Currently displayed number used everywhere.
CalcEngine::Rational m_lastVal; // Number before operation (left operand).
std::array<CalcEngine::Rational, MAXPRECDEPTH> m_parenVals; // Holding array for parenthesis values.
std::array<CalcEngine::Rational, MAXPRECDEPTH> m_precedenceVals; // Holding array for precedence values.
bool m_bError; // Error flag.
bool m_bInv; // Inverse on/off flag.
bool m_bNoPrevEqu; /* Flag for previous equals. */
uint32_t m_radix;
int32_t m_precision;
int m_cIntDigitsSav;
std::vector<uint32_t> m_decGrouping; // Holds the decimal digit grouping number
std::wstring m_numberString;
int m_nTempCom; /* Holding place for the last command. */
size_t m_openParenCount; // Number of open parentheses.
std::array<int, MAXPRECDEPTH> m_nOp; /* Holding array for parenthesis operations. */
std::array<int, MAXPRECDEPTH> m_nPrecOp; /* Holding array for precedence operations. */
size_t m_precedenceOpCount; /* Current number of precedence ops in holding. */
int m_nLastCom; // Last command entered.
ANGLE_TYPE m_angletype; // Current Angle type when in dec mode. one of deg, rad or grad
NUM_WIDTH m_numwidth; // one of qword, dword, word or byte mode.
int32_t m_dwWordBitWidth; // # of bits in currently selected word size
std::unique_ptr<std::mt19937> m_randomGeneratorEngine;
std::unique_ptr<std::uniform_real_distribution<>> m_distr;
uint64_t m_carryBit;
CHistoryCollector m_HistoryCollector; // Accumulator of each line of history as various commands are processed
std::array<CalcEngine::Rational, NUM_WIDTH_LENGTH> m_chopNumbers; // word size enforcement
std::array<std::wstring, NUM_WIDTH_LENGTH> m_maxDecimalValueStrings; // maximum values represented by a given word width based off m_chopNumbers
static std::unordered_map<std::wstring_view, std::wstring> s_engineStrings; // the string table shared across all instances
wchar_t m_decimalSeparator;
wchar_t m_groupSeparator;
private:
void ProcessCommandWorker(OpCode wParam);
void ResolveHighestPrecedenceOperation();
void HandleErrorCommand(OpCode idc);
void HandleMaxDigitsReached();
void DisplayNum(void);
int IsNumberInvalid(const std::wstring& numberString, int iMaxExp, int iMaxMantissa, uint32_t radix) const;
void DisplayAnnounceBinaryOperator();
void SetPrimaryDisplay(const std::wstring& szText, bool isError = false);
void ClearTemporaryValues();
void ClearDisplay();
CalcEngine::Rational TruncateNumForIntMath(CalcEngine::Rational const& rat);
CalcEngine::Rational SciCalcFunctions(CalcEngine::Rational const& rat, uint32_t op);
CalcEngine::Rational DoOperation(int operation, CalcEngine::Rational const& lhs, CalcEngine::Rational const& rhs);
void SetRadixTypeAndNumWidth(RADIX_TYPE radixtype, NUM_WIDTH numwidth);
int32_t DwWordBitWidthFromeNumWidth(NUM_WIDTH numwidth);
uint32_t NRadixFromRadixType(RADIX_TYPE radixtype);
double GenerateRandomNumber();
bool TryToggleBit(CalcEngine::Rational& rat, uint32_t wbitno);
void CheckAndAddLastBinOpToHistory(bool addToHistory = true);
void InitChopNumbers();
static void LoadEngineStrings(CalculationManager::IResourceProvider& resourceProvider);
static int IdStrFromCmdId(int id)
{
return id - IDC_FIRSTCONTROL + IDS_ENGINESTR_FIRST;
}
static std::vector<uint32_t> DigitGroupingStringToGroupingVector(std::wstring_view groupingString);
std::wstring GroupDigits(std::wstring_view delimiter, std::vector<uint32_t> const& grouping, std::wstring_view displayString, bool isNumNegative = false);
static int QuickLog2(int iNum);
static void ChangeBaseConstants(uint32_t radix, int maxIntDigits, int32_t precision);
void BaseOrPrecisionChanged();
friend class CalculatorEngineTests::CalcEngineTests;
};