diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 859bebaa..db98fc73 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -6,36 +6,45 @@ labels: '' assignees: '' --- - +- Search existing issues and make sure this issue is not already filed. +--> **Describe the bug** - + **Steps To Reproduce** - +4. See error +--> **Expected behavior** - + **Screenshots** - + -**Device and Application Information (please complete the following information):** +**Device and Application Information** - OS Build: - Architecture: - Application Version: - - **Additional context** - + diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 3611d4ed..0032d0b7 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -2,42 +2,42 @@ name: Feature request about: Propose a new feature in the app title: '' -labels: '' +labels: 'Enhancement' assignees: '' --- **Problem Statement** - + **Evidence or User Insights** - + **Proposal** - + **Goals** - + **Non-Goals** - + **Low-Fidelity Concept** - \ No newline at end of file + diff --git a/.github/ISSUE_TEMPLATE/localization_suggestion.md b/.github/ISSUE_TEMPLATE/localization_suggestion.md new file mode 100644 index 00000000..dd47f61d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/localization_suggestion.md @@ -0,0 +1,54 @@ +--- +name: Localization Suggestion +about: Report a problem or suggested change to Calculator's localized content. +title: '[Localization] ' +labels: 'Area: World-Readiness' +assignees: '' +--- + + +**Describe the bug** + + +**Steps To Reproduce** + + +**Expected behavior** + + +**Screenshots** + + +**Device and Application Information** + - OS Build: + - Architecture: + - Application Version: + - Region: + - Dev Version Installed: + + + +**Additional context** + diff --git a/.gitignore b/.gitignore index 80d64f53..1088272d 100644 --- a/.gitignore +++ b/.gitignore @@ -289,5 +289,7 @@ __pycache__/ # Calculator specific Generated Files/ +src/GraphControl/GraphingImplOverrides.props !/build/config/TRexDefs/** +!src/Calculator/TemporaryKey.pfx !src/CalculatorUnitTests/CalculatorUnitTests_TemporaryKey.pfx \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9bab5f16..63702de4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,7 +3,8 @@ The Calculator team encourages community feedback and contributions. Thank you f making Calculator better! There are several ways you can get involved. ## Reporting issues and suggesting new features -If Calculator is not working properly, please file a report in the [Feedback Hub](https://insider.windows.com/en-us/fb/?contextid=130&newFeedback=True). +If Calculator is not working properly, please file a report in the +[Feedback Hub](https://insider.windows.com/en-us/fb/?contextid=130&newFeedback=True). Feedback Hub reports automatically include diagnostic data, such as the version of Calculator you're using. @@ -17,21 +18,38 @@ all community interactions must abide by the [Code of Conduct](CODE_OF_CONDUCT.m ## Finding issues you can help with Looking for something to work on? -[Issues marked *good first issue*](https://github.com/Microsoft/calculator/labels/good%20first%20issue) +Issues marked [``good first issue``](https://github.com/Microsoft/calculator/labels/good%20first%20issue) are a good place to start. -You can also check [the *help wanted* tag](https://github.com/Microsoft/calculator/labels/help%20wanted) -to find other issues to help with. +You can also check the [``help wanted``](https://github.com/Microsoft/calculator/labels/help%20wanted) tag to find +other issues to help with. If you're interested in working on a fix, leave a comment to let everyone know and to help +avoid duplicated effort from others. ## Contributions we accept We welcome your contributions to the Calculator project, especially to fix bugs and to make -improvements which address the top issues reported by Calculator users. +improvements which address the top issues reported by Calculator users. Some general guidelines: -We have a high bar for new features and changes to the user experience. We prefer to evaluate -*prototypes* to ensure that the design meets users' needs before we start discussing implementation -details and reviewing code. We follow a [user-centered process for developing features](docs/NewFeatureProcess.md). -New features need sponsorship from the Calculator team, but we welcome community contributions at -many stages of the process. +* **DO** create one pull request per Issue, and ensure that the Issue is linked in the pull request. +* **DO** follow our [Coding and Style](#style-guidelines) guidelines, and keep code changes as small as possible. +* **DO** include corresponding tests whenever possible. +* **DO** check for additional occurrences of the same problem in other parts of the codebase before submitting your PR. +* **DO** [link the issue](https://github.com/blog/957-introducing-issue-mentions) you are addressing in the + pull request. +* **DO** write a good description for your pull request. More detail is better. Describe *why* the change is being + made and *why* you have chosen a particular solution. Describe any manual testing you performed to validate your change. +* **DO NOT** submit a PR unless it is linked to an Issue marked + [`triage approved`](https://github.com/Microsoft/calculator/issues?q=is%3Aissue+is%3Aopen+label%3A%22Triage%3A+Approved%22). + This enables us to have a discussion on the idea before anyone invests time in an implementation. +* **DO NOT** merge multiple changes into one PR unless they have the same root cause. +* **DO NOT** submit pure formatting/typo changes to code that has not been modified otherwise. + +We follow a [user-centered process for developing features](docs/NewFeatureProcess.md). New features +need sponsorship from the Calculator team, but we welcome community contributions at many stages of +the process. + +> Submitting a pull request for an approved Issue is not a guarantee it will be approved. +> The change must meet our high bar for code quality, architecture, and performance, as well as +> [other requirements](#docs/NewFeatureProcess.md#technical-review). ## Making changes to the code @@ -41,7 +59,8 @@ To learn how to build the code and run tests, follow the instructions in the [RE ### Style guidelines The code in this project uses several different coding styles, depending on the age and history of the code. Please attempt to match the style of surrounding code as much as possible. In new -components, prefer the patterns described in the [C++ core guidelines](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines) +components, prefer the patterns described in the +[C++ core guidelines](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines) and the [modern C++/WinRT language projections](https://docs.microsoft.com/en-us/windows/uwp/cpp-and-winrt-apis/). ### Testing @@ -61,18 +80,9 @@ to group your changes into a small number of commits which we can review one at When completing a pull request, we will generally squash your changes into a single commit. Please let us know if your pull request needs to be merged as separate commits. -## Submitting a pull request and participating in code review -Writing a good description for your pull request is crucial to help reviewers and future -maintainers understand your change. More detail is better. -- [Link the issue you're addressing in the pull request](https://github.com/blog/957-introducing-issue-mentions). -- Describe *why* the change is being made and *why* you've chosen a particular solution. -- Describe any manual testing you performed to validate your change. - -Please submit one pull request per issue. Large pull requests which have unrelated changes can be -difficult to review. - +## Review Process After submitting a pull request, members of the calculator team will review your code. We will -assign the request to an appropriate reviewer within two days. Any member of the community may +assign the request to an appropriate reviewer. Any member of the community may participate in the review, but at least one member of the Calculator team will ultimately approve the request. diff --git a/README.md b/README.md index ffba40c0..00243142 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,13 @@ Calculator ships regularly with new features and bug fixes. You can get the late - Standard Calculator functionality which offers basic operations and evaluates commands immediately as they are entered. - Scientific Calculator functionality which offers expanded operations and evaluates commands using order of operations. - Programmer Calculator functionality which offers common mathematical operations for developers including conversion between common bases. +- Date Calculation functionality which offers the difference between two dates, as well as the ability to add/subtract years, months and/or days to/from a given input date. - Calculation history and memory capabilities. - Conversion between many units of measurement. - Currency conversion based on data retrieved from [Bing](https://www.bing.com). +- [Infinite precision](https://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic) for basic + arithmetic operations (addition, subtraction, multiplication, division) so that calculations + never lose precision. ## Getting started Prerequisites: diff --git a/build/pipelines/azure-pipelines.loc.yaml b/build/pipelines/azure-pipelines.loc.yaml index d2bef95e..7c5ef246 100644 --- a/build/pipelines/azure-pipelines.loc.yaml +++ b/build/pipelines/azure-pipelines.loc.yaml @@ -15,30 +15,33 @@ name: $(BuildDefinitionName)_$(date:yyMM).$(date:dd)$(rev:rrr) jobs: - job: Localize pool: - name: Package ES Custom Demands Lab A - demands: - - ClientAlias -equals PKGESUTILAPPS - workspace: - clean: outputs + vmImage: vs2017-win2016 + variables: + skipComponentGovernanceDetection: true steps: - - checkout: self - clean: true - - task: PkgESSetupBuild@10 - displayName: Initialize Package ES + - task: MicrosoftTDBuild.tdbuild-task.tdbuild-task.TouchdownBuildTask@1 + displayName: Send resources to Touchdown Build inputs: - productName: Calculator - branchVersion: true + teamId: 86 + authId: d3dd8113-65b3-4526-bdca-a00a7d1c37ba + authKey: $(LocServiceKey) + isPreview: false + relativePathRoot: src/Calculator/Resources/en-US/ + resourceFilePath: '*.resw' + outputDirectoryRoot: src/Calculator/Resources/ - - task: PkgESTouchdownLocService@10 - displayName: Package ES Touchdown Loc Service + - script: | + cd $(Build.SourcesDirectory) + git add -A + git diff --cached --exit-code + echo ##vso[task.setvariable variable=hasChanges]%errorlevel% + git diff --cached > $(Build.ArtifactStagingDirectory)\LocalizedStrings.patch + displayName: Check for changes and create patch file + + - task: PublishPipelineArtifact@0 + displayName: Publish patch file as artifact + condition: eq(variables['hasChanges'], '1') inputs: - IsCallToServiceStepSelected: true - IsCheckedInFileSelected: true - CheckinFilesAtOriginFilePath: true - GitLocPath: Loc/Resources - LocConfigFile: build/config/LocConfigPackageEs.xml - AuthenticationMode: OAuth - ClientApplicationID: d3dd8113-65b3-4526-bdca-a00a7d1c37ba - ApplicationKeyID: $(LocServiceKey) - SendToLoc: true + artifactName: Patch + targetPath: $(Build.ArtifactStagingDirectory) \ No newline at end of file diff --git a/build/pipelines/azure-pipelines.release.yaml b/build/pipelines/azure-pipelines.release.yaml index 78b4fd90..f687ec4a 100644 --- a/build/pipelines/azure-pipelines.release.yaml +++ b/build/pipelines/azure-pipelines.release.yaml @@ -9,8 +9,8 @@ pr: none variables: versionMajor: 10 - versionMinor: 1902 - versionBuild: $[counter('10.1902.*', 0)] + versionMinor: 1904 + versionBuild: $[counter('10.1904.*', 0)] versionPatch: 0 name: '$(versionMajor).$(versionMinor).$(versionBuild).$(versionPatch)' diff --git a/build/pipelines/templates/build-app-internal.yaml b/build/pipelines/templates/build-app-internal.yaml index 8a75dcec..2de18a01 100644 --- a/build/pipelines/templates/build-app-internal.yaml +++ b/build/pipelines/templates/build-app-internal.yaml @@ -29,7 +29,7 @@ jobs: downloadDirectory: $(Build.SourcesDirectory) vstsFeed: WindowsApps vstsFeedPackage: calculator-internals - vstsPackageVersion: 0.0.7 + vstsPackageVersion: 0.0.10 - template: ./build-single-architecture.yaml parameters: diff --git a/build/pipelines/templates/package-appxbundle.yaml b/build/pipelines/templates/package-appxbundle.yaml index 2965c06e..c7735753 100644 --- a/build/pipelines/templates/package-appxbundle.yaml +++ b/build/pipelines/templates/package-appxbundle.yaml @@ -20,6 +20,8 @@ jobs: vmImage: vs2017-win2016 workspace: clean: outputs + variables: + skipComponentGovernanceDetection: true steps: - checkout: self clean: true diff --git a/build/pipelines/templates/prepare-release-internalonly.yaml b/build/pipelines/templates/prepare-release-internalonly.yaml index 6bb3b6cb..a6a4973b 100644 --- a/build/pipelines/templates/prepare-release-internalonly.yaml +++ b/build/pipelines/templates/prepare-release-internalonly.yaml @@ -17,6 +17,8 @@ jobs: name: Package ES Lab E workspace: clean: outputs + variables: + skipComponentGovernanceDetection: true steps: - checkout: self clean: true @@ -26,8 +28,8 @@ jobs: - task: PkgESSetupBuild@10 displayName: Initialize Package ES inputs: - productName: Calculator - disableWorkspace: true + productName: Calculator + disableWorkspace: true env: XES_DISABLEPROV: true @@ -44,6 +46,8 @@ jobs: - task: PkgESCodeSign@10 displayName: Send bundle to Package ES code signing service + env: + SYSTEM_ACCESSTOKEN: $(System.AccessToken) inputs: signConfigXml: build\config\SignConfig.xml inPathRoot: $(Build.ArtifactStagingDirectory)\appxBundle @@ -58,25 +62,25 @@ jobs: - task: CopyFiles@2 displayName: Copy signed AppxBundle to vpack staging folder inputs: - sourceFolder: $(Build.ArtifactStagingDirectory)\appxBundleSigned - targetFolder: $(Build.ArtifactStagingDirectory)\vpack\appxBundle + sourceFolder: $(Build.ArtifactStagingDirectory)\appxBundleSigned + targetFolder: $(Build.ArtifactStagingDirectory)\vpack\appxBundle - task: PkgESVPack@10 displayName: Create and push vpack for app env: - SYSTEM_ACCESSTOKEN: $(System.AccessToken) + SYSTEM_ACCESSTOKEN: $(System.AccessToken) inputs: - sourceDirectory: $(Build.ArtifactStagingDirectory)\vpack\appxBundle - description: VPack for the Calculator Application - pushPkgName: calculator.app - version: $(versionMajor).$(versionMinor).$(versionBuild) - owner: paxeeapps + sourceDirectory: $(Build.ArtifactStagingDirectory)\vpack\appxBundle + description: VPack for the Calculator Application + pushPkgName: calculator.app + version: $(versionMajor).$(versionMinor).$(versionBuild) + owner: paxeeapps - task: PublishBuildArtifacts@1 displayName: Publish vpack\app artifact with vpack manifest inputs: - pathtoPublish: $(XES_VPACKMANIFESTDIRECTORY)\$(XES_VPACKMANIFESTNAME) - artifactName: vpack\app + pathtoPublish: $(XES_VPACKMANIFESTDIRECTORY)\$(XES_VPACKMANIFESTNAME) + artifactName: vpack\app # TODO (macool): create and push internal test packages and test config @@ -87,7 +91,7 @@ jobs: downloadDirectory: $(Build.SourcesDirectory) vstsFeed: WindowsApps vstsFeedPackage: calculator-internals - vstsPackageVersion: 0.0.7 + vstsPackageVersion: 0.0.10 - task: PkgESStoreBrokerPackage@10 displayName: Create StoreBroker Packages diff --git a/build/pipelines/templates/run-unit-tests.yaml b/build/pipelines/templates/run-unit-tests.yaml index 6123609e..2a000118 100644 --- a/build/pipelines/templates/run-unit-tests.yaml +++ b/build/pipelines/templates/run-unit-tests.yaml @@ -14,6 +14,8 @@ jobs: name: Essential Experiences Interactive workspace: clean: outputs + variables: + skipComponentGovernanceDetection: true steps: - checkout: none diff --git a/docs/ApplicationArchitecture.md b/docs/ApplicationArchitecture.md index 0d7c2ff3..dff02965 100644 --- a/docs/ApplicationArchitecture.md +++ b/docs/ApplicationArchitecture.md @@ -153,7 +153,9 @@ The CalcEngine contains the logic for interpreting and performing operations acc ### RatPack -The RatPack (short for Rational Pack) is the core of the Calculator model and contains the logic for performing its mathematical operations. The interface to this layer is defined in [ratpak.h][ratpak.h]. +The RatPack (short for Rational Pack) is the core of the Calculator model and contains the logic for +performing its mathematical operations (using [infinite precision][Infinite Precision] arithmetic +instead of regular floating point arithmetic). The interface to this layer is defined in [ratpak.h][ratpak.h]. [References]:#################################################################################################### diff --git a/docs/NewFeatureProcess.md b/docs/NewFeatureProcess.md index 66c9a635..2a84aa27 100644 --- a/docs/NewFeatureProcess.md +++ b/docs/NewFeatureProcess.md @@ -1,7 +1,8 @@ # New feature process ## Where do I submit my idea for a new feature? -The easiest way to submit new feature requests is through [Feedback Hub](https://insider.windows.com/en-us/fb/?contextid=130). +The easiest way to submit new feature requests is through +[Feedback Hub](https://insider.windows.com/en-us/fb/?contextid=130). In Feedback Hub, any Windows user (even if they aren't on GitHub) can upvote suggestions. The Calculator team reviews these suggestions regularly, and when we're ready to work on an idea we create [feature pitch issues here on GitHub](https://github.com/Microsoft/calculator/issues?q=is%3Aissue+is%3Aopen+project%3AMicrosoft%2Fcalculator%2F1). @@ -12,73 +13,45 @@ product. The [Feature Tracking board](https://github.com/Microsoft/calculator/pr all the features we're working on and where they're at in the process. ## Do I need to follow this process? Can I just start coding and submit a PR? -You *do not* need to follow this process for bug fixes, performance improvements, or changes to the -development tools. To contribute these changes, [discuss the proposed change in an issue](https://github.com/Microsoft/calculator/issues/new) +You **do not** need to follow this process for bug fixes, performance improvements, or changes to the +development tools. To contribute these changes, +[discuss the proposed change in an issue](https://github.com/Microsoft/calculator/issues/new) and then submit a pull request. -You *do* need to follow this process for any change which "users will notice". This applies +You **do** need to follow this process for any change which "users will notice". This applies especially to new features and major visual changes. ## Step 1: Feature pitch -The feature pitch concisely describes a point of view on the problem the new feature should solve. -It will typically include these sections: +Feature pitches are submitted as issues on GitHub using the +[Feature Request template](https://github.com/Microsoft/calculator/issues/new?assignees=&labels=&template=feature_request.md&title=). +We encourage discussion on open issues, and as discussion progresses we will edit the issue description to refine the +idea until it is ready for review. -* **Problem Statement**: What problem are we trying to solve? Who’s the target audience? Is there a - customer need or pain point we need to remedy? Is there a business goal or metric we are trying - to improve? Do we have a hypothesis we want to prove or disprove? -* **Evidence or User Insights**: Why should we do this? Potential sources of data: Feedback Hub, - other GitHub issues, other anecdotes from listening to customers in person or online, request - from another team, telemetry data, user research, market or competitive research -* **Proposal**: How will the solution/feature help us solve the problem? How will it meet the - target audience’s needs? If there are business goals or metrics, how does this improve them? -* **Goals**: What you want to accomplish with this feature. Typical examples include “User Can - *perform some task*” -* **Non-Goals**: Things we are explicitly not doing or supporting or that are out of scope, - including reasons why. -* **Low-Fidelity Concept**: Show as much of the experience as needed to explain the idea. This - can be as simple as a napkin drawing but can also be a code prototype, a PowerPoint walkthrough, - or a design comp. - -The low-fidelity concept should be kept simple at this stage and refined during the pre-production -process. - -Feature pitches are submitted as issues on GitHub. We encourage discussion on open issues, and as -discussion progresses we will edit the issue description to refine the idea. +We review pitches regularly, and will approve or close issues based on whether they broadly align with the +[Calculator roadmap](https://github.com/Microsoft/calculator/blob/master/docs/Roadmap.md). Approved pitches are moved +into [pre-production](https://github.com/Microsoft/calculator/projects/1) on the feature tracking board. ## Step 2: Pre-production -In the pre-production phase, we experiment with a variety of ways to address the goals described in -the feature pitch. The output of this phase is a specification which demonstrates how the feature -will work, supported by design renderings and code prototypes as needed. Sometimes we'll learn new -things about a feature proposal during pre-production, and we'll edit or close the original pitch. +For most features, the output of this phase is a specification which describes how the feature will work, supported by +design renderings and code prototypes as needed. The original issue will continue to track the overall progress of the +feature, but we will create and iterate on spec documentation in the +[Calculator Spec repo](https://github.com/Microsoft/calculator-specs). Sometimes we'll learn new things about a feature +proposal during pre-production, and we'll edit or close the original pitch. -We welcome community participation in the pre-production process. The GitHub issue will be the -primary place to share progress updates. - -The best ideas often come from trying many ideas during the pre-production phase. To enable rapid +We welcome community participation throughout pre-production. The best ideas often come from trying many ideas during +the pre-production phase. To enable rapid experimentation, we encourage developing and sharing rough ideas—maybe even with pencil and paper—before making designs pixel-perfect or making code robust and maintainable. -### Spec review -Once there is a high-fidelity design which addresses the goals described in the original pitch, the -Microsoft product team will review the prototype and ensure all items on this checklist are -addressed: - -- [ ] Is there a high-fidelity design which gives reviewers a clear idea of how the feature will - look and function when implemented? -- [ ] Has the plan been shared with the community (documented on the wiki and updates posted in the - original issue) and have others been given an opportunity to provide suggestions? -- [ ] Are [Fluent design principles](https://docs.microsoft.com/en-us/windows/uwp/design/fluent-design-system/) - followed? If we do something which deviates from the guidelines, do we have a good reason? -- [ ] Does the design include provisions for [all users](https://docs.microsoft.com/en-us/windows/uwp/design/accessibility/designing-inclusive-software) - and [all cultures](https://docs.microsoft.com/en-us/windows/uwp/design/globalizing/guidelines-and-checklist-for-globalizing-your-app)? -- [ ] Is it technically feasible to build this feature? Take a look at the "before committing" - checklist below and identify any issues which are likely to be blockers. +After the [spec review](https://github.com/Microsoft/calculator-specs#spec-review) is completed, we will move the issue +into [production](https://github.com/Microsoft/calculator/projects/1) on the feature tracking board. In _some_ cases, +all of the details of an idea can be captured concisely in original feature pitch. When that happens, we may move ideas +directly into production. ## Step 3: Production -A feature can be implemented by the original proposer, a Microsoft team member, or by other -community members. Code contributions and testing help are greatly appreciated. Please let us know -in the issue comments if you're actively working on a feature so we can ensure it's assigned to -you. +A feature can be implemented by the original submitter, a Microsoft team member, or by other +community members. Code contributions and testing help are greatly appreciated. Please let everyone know if you're +actively working on a feature to help avoid duplicated efforts from others. You might be able to reuse code written during the prototype process, although there will typically be more work required to make the solution robust. Once the code is ready, you can begin @@ -122,7 +95,8 @@ new features, the Microsoft team considers at least these items: - [ ] Run the perf tests to measure any increase in startup time. Move work out of the startup path if possible. - [ ] If the change adds additional logging: - - [ ] All logging should use [TraceLogging](https://docs.microsoft.com/en-us/windows/desktop/tracelogging/trace-logging-about). + - [ ] All logging should use + [TraceLogging](https://docs.microsoft.com/en-us/windows/desktop/tracelogging/trace-logging-about). - [ ] Unnecessary log events should be removed, or configured so that they are collected only when needed to debug issues or measure feature usage. - [ ] If the change reads user data from files or app settings: diff --git a/docs/Roadmap.md b/docs/Roadmap.md index 93b1428e..0b969c5c 100644 --- a/docs/Roadmap.md +++ b/docs/Roadmap.md @@ -9,6 +9,7 @@ In 2019, the Windows Calculator team is focused on: * Iterating upon the existing app design based on the latest [Fluent Design guidelines](https://developer.microsoft.com/en-us/windows/apps/design) * Improving testing and diagnostics within the project * Investigating new features with a focus on addressing top user feedback, including: + * Adding graphing mode * Adding the ability for users to pin Calculator on top of other windows * Providing additional customization options * [Your feature idea here] - please review our [new feature development process](https://github.com/Microsoft/calculator/blob/master/docs/NewFeatureProcess.md) to get started! diff --git a/src/CalcManager/CEngine/CalcInput.cpp b/src/CalcManager/CEngine/CalcInput.cpp index 4994e025..1c47a8da 100644 --- a/src/CalcManager/CEngine/CalcInput.cpp +++ b/src/CalcManager/CEngine/CalcInput.cpp @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "pch.h" +#include #include "Header Files/CalcEngine.h" using namespace std; @@ -56,7 +56,7 @@ bool CalcInput::TryToggleSign(bool isIntegerMode, wstring_view maxNumStr) return true; } -bool CalcInput::TryAddDigit(unsigned int value, uint32_t radix, bool isIntegerMode, wstring_view maxNumStr, long wordBitWidth, int maxDigits) +bool CalcInput::TryAddDigit(unsigned int value, uint32_t radix, bool isIntegerMode, wstring_view maxNumStr, int32_t wordBitWidth, int maxDigits) { // Convert from an integer into a character // This includes both normal digits and alpha 'digits' for radixes > 10 diff --git a/src/CalcManager/CEngine/CalcUtils.cpp b/src/CalcManager/CEngine/CalcUtils.cpp index fe488009..15b11926 100644 --- a/src/CalcManager/CEngine/CalcUtils.cpp +++ b/src/CalcManager/CEngine/CalcUtils.cpp @@ -1,28 +1,27 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "pch.h" #include "Header Files/CalcEngine.h" #include "Header Files/CalcUtils.h" -bool IsOpInRange(WPARAM op, uint32_t x, uint32_t y) +bool IsOpInRange(OpCode op, uint32_t x, uint32_t y) { return ((op >= x) && (op <= y)); } -bool IsBinOpCode(WPARAM opCode) +bool IsBinOpCode(OpCode opCode) { return IsOpInRange(opCode, IDC_AND, IDC_PWR); } // WARNING: IDC_SIGN is a special unary op but still this doesn't catch this. Caller has to be aware // of it and catch it themselves or not needing this -bool IsUnaryOpCode(WPARAM opCode) +bool IsUnaryOpCode(OpCode opCode) { return IsOpInRange(opCode, IDC_UNARYFIRST, IDC_UNARYLAST); } -bool IsDigitOpCode(WPARAM opCode) +bool IsDigitOpCode(OpCode opCode) { return IsOpInRange(opCode, IDC_0, IDC_F); } @@ -32,7 +31,7 @@ bool IsDigitOpCode(WPARAM opCode) // so we abstract this as a separate routine. Note: There is another side to this. Some commands are not // gui mode setting to begin with, but once it is discovered it is invalid and we want to behave as though it // was never inout, we need to revert the state changes made as a result of this test -bool IsGuiSettingOpCode(WPARAM opCode) +bool IsGuiSettingOpCode(OpCode opCode) { if (IsOpInRange(opCode, IDM_HEX, IDM_BIN) || IsOpInRange(opCode, IDM_QWORD, IDM_BYTE) || diff --git a/src/CalcManager/CEngine/History.cpp b/src/CalcManager/CEngine/History.cpp index e5bb746b..74edf3cc 100644 --- a/src/CalcManager/CEngine/History.cpp +++ b/src/CalcManager/CEngine/History.cpp @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "pch.h" #include "Header Files/CalcEngine.h" #include "Command.h" #include "CalculatorVector.h" @@ -13,7 +12,7 @@ using namespace std; using namespace CalcEngine; namespace { - void IFT(HRESULT hr) + void IFT(ResultCode hr) { if (FAILED(hr)) { diff --git a/src/CalcManager/CEngine/Number.cpp b/src/CalcManager/CEngine/Number.cpp index 0d809917..fdf29e09 100644 --- a/src/CalcManager/CEngine/Number.cpp +++ b/src/CalcManager/CEngine/Number.cpp @@ -1,6 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. -#include "pch.h" +#include #include "Header Files/Number.h" using namespace std; @@ -28,10 +28,10 @@ namespace CalcEngine PNUMBER Number::ToPNUMBER() const { - PNUMBER ret = _createnum(static_cast(this->Mantissa().size()) + 1); + PNUMBER ret = _createnum(static_cast(this->Mantissa().size()) + 1); ret->sign = this->Sign(); ret->exp = this->Exp(); - ret->cdigit = static_cast(this->Mantissa().size()); + ret->cdigit = static_cast(this->Mantissa().size()); MANTTYPE *ptrRet = ret->mant; for (auto const& digit : this->Mantissa()) diff --git a/src/CalcManager/CEngine/Rational.cpp b/src/CalcManager/CEngine/Rational.cpp index 22a972a3..e116c237 100644 --- a/src/CalcManager/CEngine/Rational.cpp +++ b/src/CalcManager/CEngine/Rational.cpp @@ -1,6 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. -#include "pch.h" +#include #include "Header Files/Rational.h" using namespace std; @@ -31,7 +31,7 @@ namespace CalcEngine Rational::Rational(int32_t i) { - PRAT pr = longtorat(static_cast(i)); + PRAT pr = i32torat(static_cast(i)); m_p = Number{ pr->pp }; m_q = Number{ pr->pq }; @@ -41,7 +41,7 @@ namespace CalcEngine Rational::Rational(uint32_t ui) { - PRAT pr = Ulongtorat(static_cast(ui)); + PRAT pr = Ui32torat(static_cast(ui)); m_p = Number{ pr->pp }; m_q = Number{ pr->pq }; @@ -100,7 +100,7 @@ namespace CalcEngine addrat(&lhsRat, rhsRat, RATIONAL_PRECISION); destroyrat(rhsRat); } - catch (DWORD error) + catch (uint32_t error) { destroyrat(lhsRat); destroyrat(rhsRat); @@ -123,7 +123,7 @@ namespace CalcEngine subrat(&lhsRat, rhsRat, RATIONAL_PRECISION); destroyrat(rhsRat); } - catch (DWORD error) + catch (uint32_t error) { destroyrat(lhsRat); destroyrat(rhsRat); @@ -146,7 +146,7 @@ namespace CalcEngine mulrat(&lhsRat, rhsRat, RATIONAL_PRECISION); destroyrat(rhsRat); } - catch (DWORD error) + catch (uint32_t error) { destroyrat(lhsRat); destroyrat(rhsRat); @@ -169,7 +169,7 @@ namespace CalcEngine divrat(&lhsRat, rhsRat, RATIONAL_PRECISION); destroyrat(rhsRat); } - catch (DWORD error) + catch (uint32_t error) { destroyrat(lhsRat); destroyrat(rhsRat); @@ -182,6 +182,13 @@ namespace CalcEngine return *this; } + /// + /// Calculate the remainder after division, the sign of a result will match the sign of the current object. + /// + /// + /// This function has the same behavior as the standard C/C++ operator '%' + /// to calculate the modulus after division instead, use instead. + /// Rational& Rational::operator%=(Rational const& rhs) { PRAT lhsRat = this->ToPRAT(); @@ -189,10 +196,10 @@ namespace CalcEngine try { - modrat(&lhsRat, rhsRat); + remrat(&lhsRat, rhsRat); destroyrat(rhsRat); } - catch (DWORD error) + catch (uint32_t error) { destroyrat(lhsRat); destroyrat(rhsRat); @@ -215,7 +222,7 @@ namespace CalcEngine lshrat(&lhsRat, rhsRat, RATIONAL_BASE, RATIONAL_PRECISION); destroyrat(rhsRat); } - catch (DWORD error) + catch (uint32_t error) { destroyrat(lhsRat); destroyrat(rhsRat); @@ -238,7 +245,7 @@ namespace CalcEngine rshrat(&lhsRat, rhsRat, RATIONAL_BASE, RATIONAL_PRECISION); destroyrat(rhsRat); } - catch (DWORD error) + catch (uint32_t error) { destroyrat(lhsRat); destroyrat(rhsRat); @@ -261,7 +268,7 @@ namespace CalcEngine andrat(&lhsRat, rhsRat, RATIONAL_BASE, RATIONAL_PRECISION); destroyrat(rhsRat); } - catch (DWORD error) + catch (uint32_t error) { destroyrat(lhsRat); destroyrat(rhsRat); @@ -283,7 +290,7 @@ namespace CalcEngine orrat(&lhsRat, rhsRat, RATIONAL_BASE, RATIONAL_PRECISION); destroyrat(rhsRat); } - catch (DWORD error) + catch (uint32_t error) { destroyrat(lhsRat); destroyrat(rhsRat); @@ -305,7 +312,7 @@ namespace CalcEngine xorrat(&lhsRat, rhsRat, RATIONAL_BASE, RATIONAL_PRECISION); destroyrat(rhsRat); } - catch (DWORD error) + catch (uint32_t error) { destroyrat(lhsRat); destroyrat(rhsRat); @@ -342,6 +349,12 @@ namespace CalcEngine return lhs; } + /// + /// Calculate the remainder after division, the sign of a result will match the sign of lhs. + /// + /// + /// This function has the same behavior as the standard C/C++ operator '%', to calculate the modulus after division instead, use instead. + /// Rational operator%(Rational lhs, Rational const& rhs) { lhs %= rhs; @@ -388,7 +401,7 @@ namespace CalcEngine { result = rat_equ(lhsRat, rhsRat, RATIONAL_PRECISION); } - catch (DWORD error) + catch (uint32_t error) { destroyrat(lhsRat); destroyrat(rhsRat); @@ -416,7 +429,7 @@ namespace CalcEngine { result = rat_lt(lhsRat, rhsRat, RATIONAL_PRECISION); } - catch (DWORD error) + catch (uint32_t error) { destroyrat(lhsRat); destroyrat(rhsRat); @@ -453,7 +466,7 @@ namespace CalcEngine { result = RatToString(rat, fmt, radix, precision); } - catch (DWORD error) + catch (uint32_t error) { destroyrat(rat); throw(error); @@ -470,9 +483,9 @@ namespace CalcEngine uint64_t result; try { - result = rattoUlonglong(rat, RATIONAL_BASE, RATIONAL_PRECISION); + result = rattoUi64(rat, RATIONAL_BASE, RATIONAL_PRECISION); } - catch (DWORD error) + catch (uint32_t error) { destroyrat(rat); throw(error); diff --git a/src/CalcManager/CEngine/RationalMath.cpp b/src/CalcManager/CEngine/RationalMath.cpp index 46b5a086..4b1a4b8a 100644 --- a/src/CalcManager/CEngine/RationalMath.cpp +++ b/src/CalcManager/CEngine/RationalMath.cpp @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "pch.h" #include "Header Files/RationalMath.h" using namespace std; @@ -14,7 +13,7 @@ Rational RationalMath::Frac(Rational const& rat) { fracrat(&prat, RATIONAL_BASE, RATIONAL_PRECISION); } - catch (DWORD error) + catch (uint32_t error) { destroyrat(prat); throw(error); @@ -33,7 +32,7 @@ Rational RationalMath::Integer(Rational const& rat) { intrat(&prat, RATIONAL_BASE, RATIONAL_PRECISION); } - catch (DWORD error) + catch (uint32_t error) { destroyrat(prat); throw(error); @@ -55,7 +54,7 @@ Rational RationalMath::Pow(Rational const& base, Rational const& pow) powrat(&baseRat, powRat, RATIONAL_BASE, RATIONAL_PRECISION); destroyrat(powRat); } - catch (DWORD error) + catch (uint32_t error) { destroyrat(baseRat); destroyrat(powRat); @@ -81,7 +80,7 @@ Rational RationalMath::Fact(Rational const& rat) { factrat(&prat, RATIONAL_BASE, RATIONAL_PRECISION); } - catch (DWORD error) + catch (uint32_t error) { destroyrat(prat); throw(error); @@ -101,7 +100,7 @@ Rational RationalMath::Exp(Rational const& rat) { exprat(&prat, RATIONAL_BASE, RATIONAL_PRECISION); } - catch (DWORD error) + catch (uint32_t error) { destroyrat(prat); throw(error); @@ -121,7 +120,7 @@ Rational RationalMath::Log(Rational const& rat) { lograt(&prat, RATIONAL_PRECISION); } - catch (DWORD error) + catch (uint32_t error) { destroyrat(prat); throw(error); @@ -156,7 +155,7 @@ Rational RationalMath::Sin(Rational const& rat, ANGLE_TYPE angletype) { sinanglerat(&prat, angletype, RATIONAL_BASE, RATIONAL_PRECISION); } - catch (DWORD error) + catch (uint32_t error) { destroyrat(prat); throw(error); @@ -176,7 +175,7 @@ Rational RationalMath::Cos(Rational const& rat, ANGLE_TYPE angletype) { cosanglerat(&prat, angletype, RATIONAL_BASE, RATIONAL_PRECISION); } - catch (DWORD error) + catch (uint32_t error) { destroyrat(prat); throw(error); @@ -196,7 +195,7 @@ Rational RationalMath::Tan(Rational const& rat, ANGLE_TYPE angletype) { tananglerat(&prat, angletype, RATIONAL_BASE, RATIONAL_PRECISION); } - catch (DWORD error) + catch (uint32_t error) { destroyrat(prat); throw(error); @@ -216,7 +215,7 @@ Rational RationalMath::ASin(Rational const& rat, ANGLE_TYPE angletype) { asinanglerat(&prat, angletype, RATIONAL_BASE, RATIONAL_PRECISION); } - catch (DWORD error) + catch (uint32_t error) { destroyrat(prat); throw(error); @@ -236,7 +235,7 @@ Rational RationalMath::ACos(Rational const& rat, ANGLE_TYPE angletype) { acosanglerat(&prat, angletype, RATIONAL_BASE, RATIONAL_PRECISION); } - catch (DWORD error) + catch (uint32_t error) { destroyrat(prat); throw(error); @@ -256,7 +255,7 @@ Rational RationalMath::ATan(Rational const& rat, ANGLE_TYPE angletype) { atananglerat(&prat, angletype, RATIONAL_BASE, RATIONAL_PRECISION); } - catch (DWORD error) + catch (uint32_t error) { destroyrat(prat); throw(error); @@ -276,7 +275,7 @@ Rational RationalMath::Sinh(Rational const& rat) { sinhrat(&prat, RATIONAL_BASE, RATIONAL_PRECISION); } - catch (DWORD error) + catch (uint32_t error) { destroyrat(prat); throw(error); @@ -296,7 +295,7 @@ Rational RationalMath::Cosh(Rational const& rat) { coshrat(&prat, RATIONAL_BASE, RATIONAL_PRECISION); } - catch (DWORD error) + catch (uint32_t error) { destroyrat(prat); throw(error); @@ -316,7 +315,7 @@ Rational RationalMath::Tanh(Rational const& rat) { tanhrat(&prat, RATIONAL_BASE, RATIONAL_PRECISION); } - catch (DWORD error) + catch (uint32_t error) { destroyrat(prat); throw(error); @@ -336,7 +335,7 @@ Rational RationalMath::ASinh(Rational const& rat) { asinhrat(&prat, RATIONAL_BASE, RATIONAL_PRECISION); } - catch (DWORD error) + catch (uint32_t error) { destroyrat(prat); throw(error); @@ -356,7 +355,7 @@ Rational RationalMath::ACosh(Rational const& rat) { acoshrat(&prat, RATIONAL_BASE, RATIONAL_PRECISION); } - catch (DWORD error) + catch (uint32_t error) { destroyrat(prat); throw(error); @@ -376,7 +375,7 @@ Rational RationalMath::ATanh(Rational const& rat) { atanhrat(&prat, RATIONAL_PRECISION); } - catch (DWORD error) + catch (uint32_t error) { destroyrat(prat); throw(error); @@ -387,3 +386,33 @@ Rational RationalMath::ATanh(Rational const& rat) return result; } + +/// +/// Calculate the modulus after division, the sign of the result will match the sign of b. +/// +/// +/// When one of the operand is negative +/// the result will differ from the C/C++ operator '%' +/// use instead to calculate the remainder after division. +/// +Rational RationalMath::Mod(Rational const& a, Rational const& b) +{ + PRAT prat = a.ToPRAT(); + PRAT pn = b.ToPRAT(); + + try + { + modrat(&prat, pn); + destroyrat(pn); + } + catch (uint32_t error) + { + destroyrat(prat); + destroyrat(pn); + throw(error); + } + + auto res = Rational{ prat }; + destroyrat(prat); + return res; +} diff --git a/src/CalcManager/CEngine/calc.cpp b/src/CalcManager/CEngine/calc.cpp index 6f93a600..65e6f0d0 100644 --- a/src/CalcManager/CEngine/calc.cpp +++ b/src/CalcManager/CEngine/calc.cpp @@ -1,9 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "pch.h" +#include #include "Header Files/CalcEngine.h" - #include "CalculatorResource.h" using namespace std; @@ -15,7 +14,7 @@ using namespace CalcEngine; static constexpr int DEFAULT_MAX_DIGITS = 32; static constexpr int DEFAULT_PRECISION = 32; -static constexpr long DEFAULT_RADIX = 10; +static constexpr int32_t DEFAULT_RADIX = 10; static constexpr wchar_t DEFAULT_DEC_SEPARATOR = L'.'; static constexpr wchar_t DEFAULT_GRP_SEPARATOR = L','; @@ -25,13 +24,18 @@ static constexpr wstring_view DEFAULT_NUMBER_STR = L"0"; // Read strings for keys, errors, trig types, etc. // These will be copied from the resources to local memory. -array CCalcEngine::s_engineStrings; +unordered_map CCalcEngine::s_engineStrings; void CCalcEngine::LoadEngineStrings(CalculationManager::IResourceProvider& resourceProvider) { - for (size_t i = 0; i < s_engineStrings.size(); i++) + for (const auto& sid : g_sids) { - s_engineStrings[i] = resourceProvider.GetCEngineString(g_sids[i]); + auto locKey = wstring{ sid }; + auto locString = resourceProvider.GetCEngineString(locKey); + if (!locString.empty()) + { + s_engineStrings[locKey] = locString; + } } } @@ -168,7 +172,7 @@ void CCalcEngine::SettingsChanged() m_HistoryCollector.SetDecimalSymbol(m_decimalSeparator); // put the new decimal symbol into the table used to draw the decimal key - s_engineStrings[IDS_DECIMAL] = m_decimalSeparator; + s_engineStrings[SIDS_DECIMAL_SEPARATOR] = m_decimalSeparator; // we need to redraw to update the decimal point button numChanged = true; diff --git a/src/CalcManager/CEngine/scicomm.cpp b/src/CalcManager/CEngine/scicomm.cpp index a99397da..36130bb5 100644 --- a/src/CalcManager/CEngine/scicomm.cpp +++ b/src/CalcManager/CEngine/scicomm.cpp @@ -12,17 +12,11 @@ * * Author: \****************************************************************************/ -#include "pch.h" + +#include #include "Header Files/CalcEngine.h" #include "Header Files/CalcUtils.h" -#define IDC_RADSIN IDC_UNARYLAST+1 -#define IDC_RADCOS IDC_UNARYLAST+2 -#define IDC_RADTAN IDC_UNARYLAST+3 -#define IDC_GRADSIN IDC_UNARYLAST+4 -#define IDC_GRADCOS IDC_UNARYLAST+5 -#define IDC_GRADTAN IDC_UNARYLAST+6 - using namespace std; using namespace CalcEngine; @@ -31,9 +25,9 @@ namespace { // // returns a virtual number for precedence for the operator. We expect binary operator only, otherwise the lowest number // 0 is returned. Higher the number, higher the precedence of the operator. - INT NPrecedenceOfOp(int nopCode) + int NPrecedenceOfOp(int nopCode) { - static BYTE rgbPrec[] = { 0,0, IDC_OR,0, IDC_XOR,0, IDC_AND,1, + static uint8_t rgbPrec[] = { 0,0, IDC_OR,0, IDC_XOR,0, IDC_AND,1, IDC_ADD,2, IDC_SUB,2, IDC_RSHF,3, IDC_LSHF,3, IDC_MOD,3, IDC_DIV,3, IDC_MUL,3, IDC_PWR,4, IDC_ROOT, 4 }; unsigned int iPrec; @@ -56,7 +50,7 @@ namespace { // // When it is discovered by the state machine that at this point the input is not valid (eg. "1+)"), we want to proceed as though this input never // occurred and may be some feedback to user like Beep. The rest of input can then continue by just ignoring this command. -void CCalcEngine::HandleErrorCommand(WPARAM idc) +void CCalcEngine::HandleErrorCommand(OpCode idc) { if (!IsGuiSettingOpCode(idc)) { @@ -83,7 +77,7 @@ void CCalcEngine::ClearTemporaryValues() m_bError = false; } -void CCalcEngine::ProcessCommand(WPARAM wParam) +void CCalcEngine::ProcessCommand(OpCode wParam) { if (wParam == IDC_SET_RESULT) { @@ -94,9 +88,9 @@ void CCalcEngine::ProcessCommand(WPARAM wParam) ProcessCommandWorker(wParam); } -void CCalcEngine::ProcessCommandWorker(WPARAM wParam) +void CCalcEngine::ProcessCommandWorker(OpCode wParam) { - INT nx, ni; + int nx, ni; // Save the last command. Some commands are not saved in this manor, these // commands are: @@ -107,7 +101,7 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam) if (!IsGuiSettingOpCode(wParam)) { m_nLastCom = m_nTempCom; - m_nTempCom = (INT)wParam; + m_nTempCom = (int)wParam; } if (m_bError) @@ -185,10 +179,10 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam) // Change the operation if last input was operation. if (IsBinOpCode(m_nLastCom)) { - INT nPrev; + int nPrev; bool fPrecInvToHigher = false; // Is Precedence Inversion from lower to higher precedence happening ?? - m_nOpCode = (INT)wParam; + m_nOpCode = (int)wParam; // Check to see if by changing this binop, a Precedence inversion is happening. // Eg. 1 * 2 + and + is getting changed to ^. The previous precedence rules would have already computed @@ -285,7 +279,7 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam) DisplayAnnounceBinaryOperator(); m_lastVal = m_currentVal; - m_nOpCode = (INT)wParam; + m_nOpCode = (int)wParam; m_HistoryCollector.AddBinOpToHistory(m_nOpCode); m_bNoPrevEqu = m_bChangeOp = true; return; @@ -313,7 +307,7 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam) m_HistoryCollector.AddOpndToHistory(m_numberString, m_currentVal); } - m_HistoryCollector.AddUnaryOpToHistory((INT)wParam, m_bInv, m_angletype); + m_HistoryCollector.AddUnaryOpToHistory((int)wParam, m_bInv, m_angletype); } if ((wParam == IDC_SIN) || (wParam == IDC_COS) || (wParam == IDC_TAN) || (wParam == IDC_SINH) || (wParam == IDC_COSH) || (wParam == IDC_TANH)) @@ -326,7 +320,7 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam) } } - m_currentVal = SciCalcFunctions(m_currentVal, (DWORD)wParam); + m_currentVal = SciCalcFunctions(m_currentVal, (uint32_t)wParam); if (m_bError) return; @@ -366,7 +360,7 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam) CheckAndAddLastBinOpToHistory(); - if (TryToggleBit(m_currentVal, (DWORD)wParam - IDC_BINEDITSTART)) + if (TryToggleBit(m_currentVal, (uint32_t)wParam - IDC_BINEDITSTART)) { DisplayNum(); } @@ -397,7 +391,7 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam) cleared for CENTR */ if (nullptr != m_pCalcDisplay) { - m_pCalcDisplay->SetParenDisplayText(L""); + m_pCalcDisplay->SetParenthesisNumber(0); m_pCalcDisplay->SetExpressionDisplay(make_shared>>(), make_shared>>()); } @@ -442,7 +436,7 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam) m_nTempCom = m_nLastCom; // Put back this last saved command to the prev state so ) can be handled properly ProcessCommand(IDC_CLOSEP); m_nLastCom = m_nTempCom; // Actually this is IDC_CLOSEP - m_nTempCom = (INT)wParam; // put back in the state where last op seen was IDC_CLOSEP, and current op is IDC_EQU + m_nTempCom = (int)wParam; // put back in the state where last op seen was IDC_CLOSEP, and current op is IDC_EQU } if (!m_bNoPrevEqu) @@ -463,45 +457,12 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam) m_HistoryCollector.AddOpndToHistory(m_numberString, m_currentVal); } - do { - - if (m_nOpCode) /* Is there a valid operation around? */ - { - /* If this is the first EQU in a string, set m_holdVal=m_currentVal */ - /* Otherwise let m_currentVal=m_holdVal. This keeps m_currentVal constant */ - /* through all EQUs in a row. */ - if (m_bNoPrevEqu) - { - m_holdVal = m_currentVal; - } - else - { - m_currentVal = m_holdVal; - DisplayNum(); // to update the m_numberString - m_HistoryCollector.AddBinOpToHistory(m_nOpCode, false); - m_HistoryCollector.AddOpndToHistory(m_numberString, m_currentVal); // Adding the repeated last op to history - } - - // Do the current or last operation. - m_currentVal = DoOperation(m_nOpCode, m_currentVal, m_lastVal); - m_nPrevOpCode = m_nOpCode; - m_lastVal = m_currentVal; - - /* Check for errors. If this wasn't done, DisplayNum */ - /* would immediately overwrite any error message. */ - if (!m_bError) - DisplayNum(); - - /* No longer the first EQU. */ - m_bNoPrevEqu = false; - } - else if (!m_bError) - DisplayNum(); - - if (m_precedenceOpCount == 0 || !m_fPrecedence) - break; - - m_nOpCode = m_nPrecOp[--m_precedenceOpCount]; + // Evaluate the precedence stack. + ResolveHighestPrecedenceOperation(); + while (m_fPrecedence && m_precedenceOpCount > 0) + { + m_precedenceOpCount--; + m_nOpCode = m_nPrecOp[m_precedenceOpCount]; m_lastVal = m_precedenceVals[m_precedenceOpCount]; // Precedence Inversion check @@ -514,7 +475,9 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam) m_HistoryCollector.PopLastOpndStart(); m_bNoPrevEqu = true; - } while (m_precedenceOpCount >= 0); + + ResolveHighestPrecedenceOperation(); + } if (!m_bError) { @@ -632,7 +595,7 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam) // Set the "(=xx" indicator. if (nullptr != m_pCalcDisplay) { - m_pCalcDisplay->SetParenDisplayText(m_openParenCount ? to_wstring(m_openParenCount) : L""); + m_pCalcDisplay->SetParenthesisNumber(m_openParenCount >= 0 ? static_cast(m_openParenCount) : 0); } if (!m_bError) @@ -789,6 +752,48 @@ void CCalcEngine::ProcessCommandWorker(WPARAM wParam) } +// Helper function to resolve one item on the precedence stack. +void CCalcEngine::ResolveHighestPrecedenceOperation() +{ + // Is there a valid operation around? + if (m_nOpCode) + { + // If this is the first EQU in a string, set m_holdVal=m_currentVal + // Otherwise let m_currentVal=m_holdVal. This keeps m_currentVal constant + // through all EQUs in a row. + if (m_bNoPrevEqu) + { + m_holdVal = m_currentVal; + } + else + { + m_currentVal = m_holdVal; + DisplayNum(); // to update the m_numberString + m_HistoryCollector.AddBinOpToHistory(m_nOpCode, false); + m_HistoryCollector.AddOpndToHistory(m_numberString, m_currentVal); // Adding the repeated last op to history + } + + // Do the current or last operation. + m_currentVal = DoOperation(m_nOpCode, m_currentVal, m_lastVal); + m_nPrevOpCode = m_nOpCode; + m_lastVal = m_currentVal; + + // Check for errors. If this wasn't done, DisplayNum + // would immediately overwrite any error message. + if (!m_bError) + { + DisplayNum(); + } + + // No longer the first EQU. + m_bNoPrevEqu = false; + } + else if (!m_bError) + { + DisplayNum(); + } +} + // CheckAndAddLastBinOpToHistory // // This is a very confusing helper routine to add the last entered binary operator to the history. This is expected to @@ -857,155 +862,94 @@ void CCalcEngine::DisplayAnnounceBinaryOperator() // Unary operator Function Name table Element // since unary operators button names aren't exactly friendly for history purpose, // we have this separate table to get its localized name and for its Inv function if it exists. -typedef struct +struct FunctionNameElement { - int idsFunc; // index of string for the unary op function. Can be NULL, in which case it same as button name - int idsFuncInv; // index of string for Inv of unary op. Can be NULL, in case it is same as idsFunc - bool fDontUseInExpEval; // true if this cant be used in reverse direction as well, ie. during expression evaluation -} UFNE; + wstring degreeString; // Used by default if there are no rad or grad specific strings. + wstring inverseDegreeString; // Will fall back to degreeString if empty + + wstring radString; + wstring inverseRadString; // Will fall back to radString if empty + + wstring gradString; + wstring inverseGradString; // Will fall back to gradString if empty + + bool hasAngleStrings = ((!radString.empty()) || (!inverseRadString.empty()) || (!gradString.empty()) || (!inverseGradString.empty())); +}; // Table for each unary operator -static const UFNE rgUfne[] = +static const std::unordered_map unaryOperatorStringTable = { - /* IDC_CHOP */{ 0, IDS_FRAC, false }, - /* IDC_ROL */{ 0, 0, true }, - /* IDC_ROR */{ 0, 0, true }, + { IDC_CHOP, { L"", SIDS_FRAC} }, - /* IDC_COM */{ 0, 0, true }, - /* IDC_SIN */{ IDS_SIND, IDS_ASIND, false }, // default in this table is degrees for sin,cos & tan - /* IDC_COS */{ IDS_COSD, IDS_ACOSD, false }, - /* IDC_TAN */{ IDS_TAND, IDS_ATAND, false }, + { IDC_SIN, { SIDS_SIND, SIDS_ASIND, SIDS_SINR, SIDS_ASINR, SIDS_SING, SIDS_ASING } }, + { IDC_COS, { SIDS_COSD, SIDS_ACOSD, SIDS_COSR, SIDS_ACOSR, SIDS_COSG, SIDS_ACOSG } }, + { IDC_TAN, { SIDS_TAND, SIDS_ATAND, SIDS_TANR, SIDS_ATANR, SIDS_TANG, SIDS_ATANG } }, - /* IDC_SINH */{ 0, IDS_ASINH, false }, - /* IDC_COSH */{ 0, IDS_ACOSH, false }, - /* IDC_TANH */{ 0, IDS_ATANH, false }, + { IDC_SINH, { L"", SIDS_ASINH } }, + { IDC_COSH, { L"", SIDS_ACOSH } }, + { IDC_TANH, { L"", SIDS_ATANH } }, - /* IDC_LN */{ 0, IDS_POWE, false }, - /* IDC_LOG */{ 0, 0, false }, - /* IDC_SQRT */{ 0, 0, false }, - /* IDC_SQR */{ IDS_SQR, 0, false }, - /* IDC_CUB */{ IDS_CUBE, 0, false }, - /* IDC_FAC */{ IDS_FACT, 0, false }, - /* IDC_REC */{ IDS_REC, 0, false }, - /* IDC_DMS */{ 0, IDS_DEGREES, false }, - /* IDC_CUBEROOT */{ 0, 0, false }, - /* IDC_POW10 */{ 0, 0, false }, - /* IDC_PERCENT */{ 0, 0, false }, - - /* IDC_RADSIN */{ IDS_SINR, IDS_ASINR, false }, - /* IDC_RADCOS */{ IDS_COSR, IDS_ACOSR, false }, - /* IDC_RADTAN */{ IDS_TANR, IDS_ATANR, false }, - /* IDC_GRADCOS */{ IDS_SING, IDS_ASING, false }, - /* IDC_GRADCOS */{ IDS_COSG, IDS_ACOSG, false }, - /* IDC_GRADTAN */{ IDS_TANG, IDS_ATANG, false }, + { IDC_LN , { L"", SIDS_POWE } }, + { IDC_SQR, { SIDS_SQR } }, + { IDC_CUB, { SIDS_CUBE } }, + { IDC_FAC, { SIDS_FACT } }, + { IDC_REC, { SIDS_RECIPROC } }, + { IDC_DMS, { L"", SIDS_DEGREES } }, + { IDC_SIGN, { SIDS_NEGATE } }, + { IDC_DEGREES, { SIDS_DEGREES } } }; wstring_view CCalcEngine::OpCodeToUnaryString(int nOpCode, bool fInv, ANGLE_TYPE angletype) { - // Special cases for Sign and Degrees - if (IDC_SIGN == nOpCode) - { - return GetString(IDS_NEGATE); - } - if (IDC_DEGREES == nOpCode) - { - return GetString(IDS_DEGREES); - } - - // Correct the trigonometric functions with type of angle argument they take - if (ANGLE_RAD == angletype) - { - switch (nOpCode) - { - case IDC_SIN: - nOpCode = IDC_RADSIN; - break; - case IDC_COS: - nOpCode = IDC_RADCOS; - break; - case IDC_TAN: - nOpCode = IDC_RADTAN; - break; - } - } - else if (ANGLE_GRAD == angletype) - { - switch (nOpCode) - { - case IDC_SIN: - nOpCode = IDC_GRADSIN; - break; - case IDC_COS: - nOpCode = IDC_GRADCOS; - break; - case IDC_TAN: - nOpCode = IDC_GRADTAN; - break; - } - } - // Try to lookup the ID in the UFNE table - int ids = 0; - int iufne = nOpCode - IDC_UNARYFIRST; - if (iufne >= 0 && (size_t)iufne < size(rgUfne)) + wstring ids = L""; + + if (auto pair = unaryOperatorStringTable.find(nOpCode); pair != unaryOperatorStringTable.end()) { - if (fInv) + const FunctionNameElement& element = pair->second; + if (!element.hasAngleStrings || ANGLE_DEG == angletype) { - ids = rgUfne[iufne].idsFuncInv; + if (fInv) + { + ids = element.inverseDegreeString; + } + + if (ids.empty()) + { + ids = element.degreeString; + } } - if (0 == ids) + else if (ANGLE_RAD == angletype) { - ids = rgUfne[iufne].idsFunc; + if (fInv) + { + ids = element.inverseRadString; + } + if (ids.empty()) + { + ids = element.radString; + } } + else if (ANGLE_GRAD == angletype) + { + if (fInv) + { + ids = element.inverseGradString; + } + if (ids.empty()) + { + ids = element.gradString; + } + } + } + + if (!ids.empty()) + { + return GetString(ids); } // If we didn't find an ID in the table, use the op code. - if (0 == ids) - { - ids = IdStrFromCmdId(nOpCode); - } - - return GetString(ids); -} - -// -// Sets the Angle Mode for special unary op IDC's which are used to index to the table rgUfne -// and returns the equivalent plain IDC for trigonometric function. If it isn't a trigonometric function -// returns the passed in idc itself. -int CCalcEngine::IdcSetAngleTypeDecMode(int idc) -{ - int idcAngleCmd = IDM_DEG; - - switch (idc) - { - case IDC_RADSIN: - idcAngleCmd = IDM_RAD; - idc = IDC_SIN; - break; - case IDC_RADCOS: - idcAngleCmd = IDM_RAD; - idc = IDC_COS; - break; - case IDC_RADTAN: - idcAngleCmd = IDM_RAD; - idc = IDC_TAN; - break; - case IDC_GRADSIN: - idcAngleCmd = IDM_GRAD; - idc = IDC_SIN; - break; - case IDC_GRADCOS: - idcAngleCmd = IDM_GRAD; - idc = IDC_COS; - break; - case IDC_GRADTAN: - idcAngleCmd = IDM_GRAD; - idc = IDC_TAN; - break; - } - ProcessCommand(idcAngleCmd); - return idc; - + return OpCodeToString(nOpCode); } bool CCalcEngine::IsCurrentTooBigForTrig() @@ -1060,7 +1004,7 @@ wstring CCalcEngine::GetStringForDisplay(Rational const& rat, uint32_t radix) result = tempRat.ToString(radix, m_nFE, m_precision); } - catch (DWORD) + catch (uint32_t) { } } diff --git a/src/CalcManager/CEngine/scidisp.cpp b/src/CalcManager/CEngine/scidisp.cpp index e01cc239..1ef88799 100644 --- a/src/CalcManager/CEngine/scidisp.cpp +++ b/src/CalcManager/CEngine/scidisp.cpp @@ -12,7 +12,9 @@ * * Author: \****************************************************************************/ -#include "pch.h" + +#include +#include #include "Header Files/CalcEngine.h" using namespace std; @@ -39,7 +41,7 @@ typedef struct { Rational value; int32_t precision; uint32_t radix; - INT nFE; + int nFE; NUM_WIDTH numwidth; bool fIntMath; bool bRecord; diff --git a/src/CalcManager/CEngine/scifunc.cpp b/src/CalcManager/CEngine/scifunc.cpp index 9c7ef7a3..c2341752 100644 --- a/src/CalcManager/CEngine/scifunc.cpp +++ b/src/CalcManager/CEngine/scifunc.cpp @@ -16,7 +16,6 @@ /*** ***/ /*** ***/ /**************************************************************************/ -#include "pch.h" #include "Header Files/CalcEngine.h" using namespace std; @@ -24,7 +23,7 @@ using namespace CalcEngine; using namespace CalcEngine::RationalMath; /* Routines for more complex mathematical functions/error checking. */ -CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& rat, DWORD op) +CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& rat, uint32_t op) { Rational result{}; try @@ -205,7 +204,7 @@ CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& r } } // end switch( op ) } - catch (DWORD nErrCode) + catch (uint32_t nErrCode) { DisplayError(nErrCode); result = rat; @@ -215,9 +214,9 @@ CalcEngine::Rational CCalcEngine::SciCalcFunctions(CalcEngine::Rational const& r } /* Routine to display error messages and set m_bError flag. Errors are */ -/* called with DisplayError (n), where n is a DWORD between 0 and 5. */ +/* called with DisplayError (n), where n is a uint32_t between 0 and 5. */ -void CCalcEngine::DisplayError(DWORD nError) +void CCalcEngine::DisplayError(uint32_t nError) { wstring errorString{ GetString(IDS_ERRORS_FIRST + SCODE_CODE(nError)) }; diff --git a/src/CalcManager/CEngine/scioper.cpp b/src/CalcManager/CEngine/scioper.cpp index 06fe3450..f8d04855 100644 --- a/src/CalcManager/CEngine/scioper.cpp +++ b/src/CalcManager/CEngine/scioper.cpp @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "pch.h" #include "Header Files/CalcEngine.h" using namespace CalcEngine; @@ -78,7 +77,7 @@ CalcEngine::Rational CCalcEngine::DoOperation(int operation, CalcEngine::Rationa case IDC_DIV: case IDC_MOD: { - int iNumeratorSign = 1, iDenominatorSign = 1, iFinalSign = 1; + int iNumeratorSign = 1, iDenominatorSign = 1; auto temp = result; result = rhs; @@ -107,20 +106,30 @@ CalcEngine::Rational CCalcEngine::DoOperation(int operation, CalcEngine::Rationa if (operation == IDC_DIV) { - iFinalSign = iNumeratorSign * iDenominatorSign; result /= temp; + if (m_fIntegerMode && (iNumeratorSign * iDenominatorSign) == -1) + { + result = -(Integer(result)); + } } else { - iFinalSign = iNumeratorSign; - result %= temp; - } + if (m_fIntegerMode) + { + // Programmer mode, use remrat (remainder after division) + result %= temp; - if (m_fIntegerMode && iFinalSign == -1) - { - result = -(Integer(result)); + if (iNumeratorSign == -1) + { + result = -(Integer(result)); + } + } + else + { + //other modes, use modrat (modulus after division) + result = Mod(result, temp); + } } - break; } @@ -133,7 +142,7 @@ CalcEngine::Rational CCalcEngine::DoOperation(int operation, CalcEngine::Rationa break; } } - catch (DWORD dwErrCode) + catch (uint32_t dwErrCode) { DisplayError(dwErrCode); diff --git a/src/CalcManager/CEngine/sciset.cpp b/src/CalcManager/CEngine/sciset.cpp index 95451dc9..ca715be5 100644 --- a/src/CalcManager/CEngine/sciset.cpp +++ b/src/CalcManager/CEngine/sciset.cpp @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "pch.h" #include "Header Files/CalcEngine.h" using namespace CalcEngine; @@ -51,10 +50,10 @@ void CCalcEngine::SetRadixTypeAndNumWidth(RADIX_TYPE radixtype, NUM_WIDTH numwid DisplayNum(); } -LONG CCalcEngine::DwWordBitWidthFromeNumWidth(NUM_WIDTH /*numwidth*/) +int32_t CCalcEngine::DwWordBitWidthFromeNumWidth(NUM_WIDTH /*numwidth*/) { static constexpr int nBitMax[] = { 64, 32, 16, 8 }; - LONG wmax = nBitMax[0]; + int32_t wmax = nBitMax[0]; if (m_numwidth >= 0 && (size_t)m_numwidth < size(nBitMax)) { @@ -77,9 +76,9 @@ uint32_t CCalcEngine::NRadixFromRadixType(RADIX_TYPE radixtype) } // Toggles a given bit into the number representation. returns true if it changed it actually. -bool CCalcEngine::TryToggleBit(CalcEngine::Rational& rat, DWORD wbitno) +bool CCalcEngine::TryToggleBit(CalcEngine::Rational& rat, uint32_t wbitno) { - DWORD wmax = DwWordBitWidthFromeNumWidth(m_numwidth); + uint32_t wmax = DwWordBitWidthFromeNumWidth(m_numwidth); if (wbitno >= wmax) { return false; // ignore error cant happen diff --git a/src/CalcManager/CalcManager.vcxproj b/src/CalcManager/CalcManager.vcxproj index 4a098141..4d03a5c9 100644 --- a/src/CalcManager/CalcManager.vcxproj +++ b/src/CalcManager/CalcManager.vcxproj @@ -157,6 +157,7 @@ $(SolutionDir)..\src\;%(AdditionalIncludeDirectories) Level4 true + pch.h Console @@ -173,6 +174,7 @@ $(SolutionDir)..\src\;%(AdditionalIncludeDirectories) Level4 true + pch.h Console @@ -189,6 +191,7 @@ $(SolutionDir)..\src\;%(AdditionalIncludeDirectories) Level4 true + pch.h Console @@ -205,6 +208,7 @@ $(SolutionDir)..\src\;%(AdditionalIncludeDirectories) Level4 true + pch.h Console @@ -222,6 +226,7 @@ $(SolutionDir)..\src\;%(AdditionalIncludeDirectories) Level4 true + pch.h Console @@ -238,6 +243,7 @@ $(SolutionDir)..\src\;%(AdditionalIncludeDirectories) Level4 true + pch.h Console @@ -254,6 +260,7 @@ $(SolutionDir)..\src\;%(AdditionalIncludeDirectories) Level4 true + pch.h Console @@ -270,6 +277,7 @@ $(SolutionDir)..\src\;%(AdditionalIncludeDirectories) Level4 true + pch.h Console @@ -278,7 +286,6 @@ - diff --git a/src/CalcManager/CalculatorHistory.cpp b/src/CalcManager/CalculatorHistory.cpp index 6b18a8e8..935ea8da 100644 --- a/src/CalcManager/CalculatorHistory.cpp +++ b/src/CalcManager/CalculatorHistory.cpp @@ -1,14 +1,13 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "pch.h" +#include #include "CalculatorHistory.h" using namespace std; using namespace CalculationManager; -CalculatorHistory::CalculatorHistory(CALCULATOR_MODE eMode, size_t maxSize) : - m_mode(eMode), +CalculatorHistory::CalculatorHistory(size_t maxSize) : m_maxHistorySize(maxSize) {} @@ -35,15 +34,13 @@ unsigned int CalculatorHistory::AddToHistory(_In_ shared_ptr const &spHistoryItem) { - int lastIndex; - if (m_historyItems.size() >= m_maxHistorySize) { m_historyItems.erase(m_historyItems.begin()); } m_historyItems.push_back(spHistoryItem); - lastIndex = static_cast(m_historyItems.size() - 1); + unsigned int lastIndex = static_cast(m_historyItems.size() - 1); return lastIndex; } diff --git a/src/CalcManager/CalculatorHistory.h b/src/CalcManager/CalculatorHistory.h index aececbda..ea87f857 100644 --- a/src/CalcManager/CalculatorHistory.h +++ b/src/CalcManager/CalculatorHistory.h @@ -31,19 +31,18 @@ namespace CalculationManager { public: - CalculatorHistory(CALCULATOR_MODE eMode, const size_t maxSize); + CalculatorHistory(const size_t maxSize); unsigned int AddToHistory(_In_ std::shared_ptr>> const &spTokens, _In_ std::shared_ptr>> const &spCommands, std::wstring_view result); std::vector> const& GetHistory(); std::shared_ptr const& GetHistoryItem(unsigned int uIdx); void ClearHistory(); unsigned int AddItem(_In_ std::shared_ptr const &spHistoryItem); bool RemoveItem(unsigned int uIdx); - const size_t MaxHistorySize() const { return m_maxHistorySize; } + size_t MaxHistorySize() const { return m_maxHistorySize; } ~CalculatorHistory(void); private: std::vector> m_historyItems; - CALCULATOR_MODE m_mode; const size_t m_maxHistorySize; }; } diff --git a/src/CalcManager/CalculatorManager.cpp b/src/CalcManager/CalculatorManager.cpp index 4d13c4a0..e640bd94 100644 --- a/src/CalcManager/CalculatorManager.cpp +++ b/src/CalcManager/CalculatorManager.cpp @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "pch.h" +#include // for UCHAR_MAX #include "Header Files/CalcEngine.h" #include "CalculatorManager.h" #include "CalculatorResource.h" @@ -24,15 +24,15 @@ namespace CalculationManager { CalculatorManager::CalculatorManager(_In_ ICalcDisplay* displayCallback, _In_ IResourceProvider* resourceProvider) : m_displayCallback(displayCallback), + m_currentCalculatorEngine(nullptr), m_resourceProvider(resourceProvider), + m_inHistoryItemLoadMode(false), + m_persistedPrimaryValue(), + m_isExponentialFormat(false), m_currentDegreeMode(Command::CommandNULL), m_savedDegreeMode(Command::CommandDEG), - m_isExponentialFormat(false), - m_persistedPrimaryValue(), - m_currentCalculatorEngine(nullptr), - m_pStdHistory(new CalculatorHistory(CM_STD, MAX_HISTORY_ITEMS)), - m_pSciHistory(new CalculatorHistory(CM_SCI, MAX_HISTORY_ITEMS)), - m_inHistoryItemLoadMode(false) + m_pStdHistory(new CalculatorHistory(MAX_HISTORY_ITEMS)), + m_pSciHistory(new CalculatorHistory(MAX_HISTORY_ITEMS)) { CCalcEngine::InitialOneTimeOnlySetup(*m_resourceProvider); } @@ -111,9 +111,9 @@ namespace CalculationManager /// Callback from the engine /// /// string containing the parenthesis count - void CalculatorManager::SetParenDisplayText(const wstring& parenthesisCount) + void CalculatorManager::SetParenthesisNumber(_In_ unsigned int parenthesisCount) { - m_displayCallback->SetParenDisplayText(parenthesisCount); + m_displayCallback->SetParenthesisNumber(parenthesisCount); } /// @@ -212,7 +212,7 @@ namespace CalculationManager /// /// Send command to the Calc Engine - /// Cast Command Enum to WPARAM. + /// Cast Command Enum to OpCode. /// Handle special commands such as mode change and combination of two commands. /// /// Enum Command @@ -235,7 +235,7 @@ namespace CalculationManager this->SetProgrammerMode(); break; default: - m_currentCalculatorEngine->ProcessCommand(static_cast(command)); + m_currentCalculatorEngine->ProcessCommand(static_cast(command)); } m_savedCommands.clear(); // Clear the previous command history @@ -263,38 +263,38 @@ namespace CalculationManager switch (command) { case Command::CommandASIN: - m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandINV)); - m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandSIN)); + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandINV)); + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandSIN)); break; case Command::CommandACOS: - m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandINV)); - m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandCOS)); + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandINV)); + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandCOS)); break; case Command::CommandATAN: - m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandINV)); - m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandTAN)); + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandINV)); + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandTAN)); break; case Command::CommandPOWE: - m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandINV)); - m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandLN)); + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandINV)); + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandLN)); break; case Command::CommandASINH: - m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandINV)); - m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandSINH)); + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandINV)); + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandSINH)); break; case Command::CommandACOSH: - m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandINV)); - m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandCOSH)); + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandINV)); + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandCOSH)); break; case Command::CommandATANH: - m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandINV)); - m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandTANH)); + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandINV)); + m_currentCalculatorEngine->ProcessCommand(static_cast(Command::CommandTANH)); break; case Command::CommandFE: m_isExponentialFormat = !m_isExponentialFormat; - // fall through + [[fallthrough]]; default: - m_currentCalculatorEngine->ProcessCommand(static_cast(command)); + m_currentCalculatorEngine->ProcessCommand(static_cast(command)); break; } } @@ -308,7 +308,10 @@ namespace CalculationManager unsigned char CalculatorManager::MapCommandForSerialize(Command command) { unsigned int commandToSave = static_cast(command); - commandToSave > UCHAR_MAX ? commandToSave -= UCHAR_MAX : commandToSave; + if (commandToSave > UCHAR_MAX) + { + commandToSave -= UCHAR_MAX; + } return static_cast(commandToSave); } @@ -360,7 +363,7 @@ namespace CalculationManager /// Serialized Rational of primary display void CalculatorManager::DeSerializePrimaryDisplay(const vector &serializedPrimaryDisplay) { - if (serializedPrimaryDisplay.size() == 0) + if (serializedPrimaryDisplay.empty()) { return; } diff --git a/src/CalcManager/CalculatorManager.h b/src/CalcManager/CalculatorManager.h index 69f4f75c..e00dc243 100644 --- a/src/CalcManager/CalculatorManager.h +++ b/src/CalcManager/CalculatorManager.h @@ -42,7 +42,7 @@ namespace CalculationManager MemorizedNumberClear = 335 }; - class CalculatorManager sealed : public ICalcDisplay + class CalculatorManager final : public ICalcDisplay { private: ICalcDisplay* const m_displayCallback; @@ -94,7 +94,7 @@ namespace CalculationManager void SetExpressionDisplay(_Inout_ std::shared_ptr>> const &tokens, _Inout_ std::shared_ptr>> const &commands) override; void SetMemorizedNumbers(_In_ const std::vector& memorizedNumbers) override; void OnHistoryItemAdded(_In_ unsigned int addedItemIndex) override; - void SetParenDisplayText(const std::wstring& parenthesisCount) override; + void SetParenthesisNumber(_In_ unsigned int parenthesisCount) override; void OnNoRightParenAdded() override; void DisplayPasteError(); void MaxDigitsReached() override; @@ -141,7 +141,7 @@ namespace CalculationManager std::shared_ptr const& GetHistoryItem(_In_ unsigned int uIdx); bool RemoveHistoryItem(_In_ unsigned int uIdx); void ClearHistory(); - const size_t MaxHistorySize() const { return m_pHistory->MaxHistorySize(); } + size_t MaxHistorySize() const { return m_pHistory->MaxHistorySize(); } CalculationManager::Command GetCurrentDegreeMode(); void SetHistory(_In_ CALCULATOR_MODE eMode, _In_ std::vector> const& history); void SetInHistoryItemLoadMode(_In_ bool isHistoryItemLoadMode); diff --git a/src/CalcManager/CalculatorVector.h b/src/CalcManager/CalculatorVector.h index 7fad7e7d..e9f1b8dc 100644 --- a/src/CalcManager/CalculatorVector.h +++ b/src/CalcManager/CalculatorVector.h @@ -1,15 +1,22 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #pragma once +#include +#include +#include +#include "Ratpack/CalcErr.h" +#include // for std::out_of_range +#include // for SAL + template class CalculatorVector { public: - HRESULT GetAt(_In_opt_ unsigned int index, _Out_ TType *item) + ResultCode GetAt(_In_opt_ unsigned int index, _Out_ TType *item) { - HRESULT hr = S_OK; + ResultCode hr = S_OK; try { *item = m_vector.at(index); @@ -21,15 +28,15 @@ public: return hr; } - HRESULT GetSize(_Out_ unsigned int *size) + ResultCode GetSize(_Out_ unsigned int *size) { *size = static_cast(m_vector.size()); return S_OK; } - HRESULT SetAt(_In_ unsigned int index, _In_opt_ TType item) + ResultCode SetAt(_In_ unsigned int index, _In_opt_ TType item) { - HRESULT hr = S_OK; + ResultCode hr = S_OK; try { m_vector[index] = item; @@ -41,9 +48,9 @@ public: return hr; } - HRESULT RemoveAt(_In_ unsigned int index) + ResultCode RemoveAt(_In_ unsigned int index) { - HRESULT hr = S_OK; + ResultCode hr = S_OK; if (index < m_vector.size()) { m_vector.erase(m_vector.begin() + index); @@ -55,9 +62,9 @@ public: return hr; } - HRESULT InsertAt(_In_ unsigned int index, _In_ TType item) + ResultCode InsertAt(_In_ unsigned int index, _In_ TType item) { - HRESULT hr = S_OK; + ResultCode hr = S_OK; try { auto iter = m_vector.begin() + index; @@ -70,9 +77,9 @@ public: return hr; } - HRESULT Truncate(_In_ unsigned int index) + ResultCode Truncate(_In_ unsigned int index) { - HRESULT hr = S_OK; + ResultCode hr = S_OK; if (index < m_vector.size()) { auto startIter = m_vector.begin() + index; @@ -85,9 +92,9 @@ public: return hr; } - HRESULT Append(_In_opt_ TType item) + ResultCode Append(_In_opt_ TType item) { - HRESULT hr = S_OK; + ResultCode hr = S_OK; try { m_vector.push_back(item); @@ -99,21 +106,21 @@ public: return hr; } - HRESULT RemoveAtEnd() + ResultCode RemoveAtEnd() { m_vector.erase(--(m_vector.end())); return S_OK; } - HRESULT Clear() + ResultCode Clear() { m_vector.clear(); return S_OK; } - HRESULT GetString(_Out_ std::wstring* expression) + ResultCode GetString(_Out_ std::wstring* expression) { - HRESULT hr = S_OK; + ResultCode hr = S_OK; unsigned int nTokens = 0; std::pair currentPair; hr = this->GetSize(&nTokens); @@ -144,7 +151,7 @@ public: return hr; } - HRESULT GetExpressionSuffix(_Out_ std::wstring* suffix) + ResultCode GetExpressionSuffix(_Out_ std::wstring* suffix) { *suffix = L" ="; return S_OK; diff --git a/src/CalcManager/Command.h b/src/CalcManager/Command.h index e6eeb8ac..4d98d012 100644 --- a/src/CalcManager/Command.h +++ b/src/CalcManager/Command.h @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #pragma once diff --git a/src/CalcManager/ExpressionCommand.cpp b/src/CalcManager/ExpressionCommand.cpp index 08ee293c..9fc87708 100644 --- a/src/CalcManager/ExpressionCommand.cpp +++ b/src/CalcManager/ExpressionCommand.cpp @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "pch.h" +#include #include "Header Files/CCommand.h" #include "CalculatorVector.h" #include "ExpressionCommand.h" @@ -98,8 +98,8 @@ void CBinaryCommand::Accept(_In_ ISerializeCommandVisitor &commandVisitor) COpndCommand::COpndCommand(shared_ptr> const &commands, bool fNegative, bool fDecimal, bool fSciFmt) : m_commands(commands), m_fNegative(fNegative), - m_fDecimal(fDecimal), m_fSciFmt(fSciFmt), + m_fDecimal(fDecimal), m_fInitialized(false), m_value{} {} diff --git a/src/CalcManager/ExpressionCommandInterface.h b/src/CalcManager/ExpressionCommandInterface.h index ce89dd81..94bae836 100644 --- a/src/CalcManager/ExpressionCommandInterface.h +++ b/src/CalcManager/ExpressionCommandInterface.h @@ -1,7 +1,9 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #pragma once + +#include // for std::shared_ptr #include "CalculatorVector.h" #include "Command.h" diff --git a/src/CalcManager/Header Files/CCommand.h b/src/CalcManager/Header Files/CCommand.h index 2fc08b3c..9530b5c5 100644 --- a/src/CalcManager/Header Files/CCommand.h +++ b/src/CalcManager/Header Files/CCommand.h @@ -13,6 +13,8 @@ * \****************************************************************************/ +#pragma once + // The following are the valid id's which can be passed to CCalcEngine::ProcessCommand #define IDM_HEX 313 diff --git a/src/CalcManager/Header Files/CalcEngine.h b/src/CalcManager/Header Files/CalcEngine.h index 3e151e2a..c84f2d55 100644 --- a/src/CalcManager/Header Files/CalcEngine.h +++ b/src/CalcManager/Header Files/CalcEngine.h @@ -22,6 +22,7 @@ #include "RadixType.h" #include "History.h" // for History Collector #include "CalcInput.h" +#include "CalcUtils.h" #include "ICalcDisplay.h" #include "Rational.h" #include "RationalMath.h" @@ -44,7 +45,7 @@ namespace CalculationManager class IResourceProvider; } -namespace CalculatorUnitTests +namespace CalculatorEngineTests { class CalcEngineTests; } @@ -52,8 +53,8 @@ namespace CalculatorUnitTests class CCalcEngine { public: CCalcEngine(bool fPrecedence, bool fIntegerMode, CalculationManager::IResourceProvider* const pResourceProvider, __in_opt ICalcDisplay *pCalcDisplay, __in_opt std::shared_ptr pHistoryDisplay); - void ProcessCommand(WPARAM wID); - void DisplayError (DWORD nError); + void ProcessCommand(OpCode wID); + void DisplayError (uint32_t nError); std::unique_ptr PersistedMemObject(); void PersistedMemObject(CalcEngine::Rational const& memObject); bool FInErrorState() { return m_bError; } @@ -71,7 +72,8 @@ public: // 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[ids]; } + static std::wstring_view GetString(int ids) { return s_engineStrings[std::to_wstring(ids)]; } + static std::wstring_view GetString(std::wstring 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); @@ -116,19 +118,20 @@ private: 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. - LONG m_dwWordBitWidth; // # of bits in currently selected word size + int32_t m_dwWordBitWidth; // # of bits in currently selected word size CHistoryCollector m_HistoryCollector; // Accumulator of each line of history as various commands are processed std::array m_chopNumbers; // word size enforcement std::array m_maxDecimalValueStrings; // maximum values represented by a given word width based off m_chopNumbers - static std::array s_engineStrings; // the string table shared across all instances + static std::unordered_map s_engineStrings; // the string table shared across all instances wchar_t m_decimalSeparator; wchar_t m_groupSeparator; private: - void ProcessCommandWorker(WPARAM wParam); - void HandleErrorCommand(WPARAM idc); + 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; @@ -136,20 +139,19 @@ private: void SetPrimaryDisplay(const std::wstring& szText, bool isError = false); void ClearTemporaryValues(); CalcEngine::Rational TruncateNumForIntMath(CalcEngine::Rational const& rat); - CalcEngine::Rational SciCalcFunctions(CalcEngine::Rational const& rat, DWORD op); + 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); - LONG DwWordBitWidthFromeNumWidth(NUM_WIDTH numwidth); + int32_t DwWordBitWidthFromeNumWidth(NUM_WIDTH numwidth); uint32_t NRadixFromRadixType( RADIX_TYPE radixtype); - bool TryToggleBit(CalcEngine::Rational& rat, DWORD wbitno); + bool TryToggleBit(CalcEngine::Rational& rat, uint32_t wbitno); void CheckAndAddLastBinOpToHistory(bool addToHistory = true); - int IdcSetAngleTypeDecMode(int idc); void InitChopNumbers(); static void LoadEngineStrings(CalculationManager::IResourceProvider& resourceProvider); - static int IdStrFromCmdId(int id) { return id - IDC_FIRSTCONTROL + IDS_FIRSTENGSTR; } + static int IdStrFromCmdId(int id) { return id - IDC_FIRSTCONTROL + IDS_ENGINESTR_FIRST; } static std::vector DigitGroupingStringToGroupingVector(std::wstring_view groupingString); std::wstring GroupDigits(std::wstring_view delimiter, std::vector const& grouping, std::wstring_view displayString, bool isNumNegative = false); @@ -158,5 +160,5 @@ private: static void ChangeBaseConstants(uint32_t radix, int maxIntDigits, int32_t precision); void BaseOrPrecisionChanged(); - friend class CalculatorUnitTests::CalcEngineTests; + friend class CalculatorEngineTests::CalcEngineTests; }; diff --git a/src/CalcManager/Header Files/CalcInput.h b/src/CalcManager/Header Files/CalcInput.h index 60d628c1..b39021e4 100644 --- a/src/CalcManager/Header Files/CalcInput.h +++ b/src/CalcManager/Header Files/CalcInput.h @@ -47,7 +47,7 @@ namespace CalcEngine void Clear(); bool TryToggleSign(bool isIntegerMode, std::wstring_view maxNumStr); - bool TryAddDigit(unsigned int value, uint32_t radix, bool isIntegerMode, std::wstring_view maxNumStr, long wordBitWidth, int maxDigits); + bool TryAddDigit(unsigned int value, uint32_t radix, bool isIntegerMode, std::wstring_view maxNumStr, int32_t wordBitWidth, int maxDigits); bool TryAddDecimalPt(); bool HasDecimalPt(); bool TryBeginExponent(); diff --git a/src/CalcManager/Header Files/CalcUtils.h b/src/CalcManager/Header Files/CalcUtils.h index 1e0dcae3..bd800783 100644 --- a/src/CalcManager/Header Files/CalcUtils.h +++ b/src/CalcManager/Header Files/CalcUtils.h @@ -3,11 +3,13 @@ #pragma once -bool IsOpInRange(WPARAM op, uint32_t x, uint32_t y); -bool IsBinOpCode(WPARAM opCode); +using OpCode = uintptr_t; + +bool IsOpInRange(OpCode op, uint32_t x, uint32_t y); +bool IsBinOpCode(OpCode opCode); // WARNING: IDC_SIGN is a special unary op but still this doesn't catch this. Caller has to be aware // of it and catch it themselves or not needing this -bool IsUnaryOpCode(WPARAM opCode); -bool IsDigitOpCode(WPARAM opCode); -bool IsGuiSettingOpCode(WPARAM opCode); +bool IsUnaryOpCode(OpCode opCode); +bool IsDigitOpCode(OpCode opCode); +bool IsGuiSettingOpCode(OpCode opCode); diff --git a/src/CalcManager/Header Files/EngineStrings.h b/src/CalcManager/Header Files/EngineStrings.h index 2ada6bba..89d624bf 100644 --- a/src/CalcManager/Header Files/EngineStrings.h +++ b/src/CalcManager/Header Files/EngineStrings.h @@ -13,327 +13,284 @@ * Created: 13-Feb-2008 * \****************************************************************************/ -#define IDS_FIRSTENGSTR IDS_ENGINESTR_FIRST -#define IDS_DECIMAL 4 +#pragma once -// All unary op function names for easy history reading -// This is where the first string after all the commands in order have been placed, should be placed -// keeping in consecutive helps us to allocate 1 string table and index them -#define IDS_FNSZFIRST (IDC_F -IDC_FIRSTCONTROL)+1 +#include -#define IDS_FRAC IDS_FNSZFIRST - -#define IDS_SIND IDS_FNSZFIRST+1 -#define IDS_COSD IDS_FNSZFIRST+2 -#define IDS_TAND IDS_FNSZFIRST+3 -#define IDS_ASIND IDS_FNSZFIRST+4 -#define IDS_ACOSD IDS_FNSZFIRST+5 -#define IDS_ATAND IDS_FNSZFIRST+6 - -#define IDS_SINR IDS_FNSZFIRST+7 -#define IDS_COSR IDS_FNSZFIRST+8 -#define IDS_TANR IDS_FNSZFIRST+9 -#define IDS_ASINR IDS_FNSZFIRST+10 -#define IDS_ACOSR IDS_FNSZFIRST+11 -#define IDS_ATANR IDS_FNSZFIRST+12 - -#define IDS_SING IDS_FNSZFIRST+13 -#define IDS_COSG IDS_FNSZFIRST+14 -#define IDS_TANG IDS_FNSZFIRST+15 -#define IDS_ASING IDS_FNSZFIRST+16 -#define IDS_ACOSG IDS_FNSZFIRST+17 -#define IDS_ATANG IDS_FNSZFIRST+18 - -#define IDS_ASINH IDS_FNSZFIRST+19 -#define IDS_ACOSH IDS_FNSZFIRST+20 -#define IDS_ATANH IDS_FNSZFIRST+21 -#define IDS_POWE IDS_FNSZFIRST+22 -#define IDS_POW10 IDS_FNSZFIRST+23 -#define IDS_SQRT IDS_FNSZFIRST+24 -#define IDS_SQR IDS_FNSZFIRST+25 -#define IDS_CUBE IDS_FNSZFIRST+26 -#define IDS_CUBERT IDS_FNSZFIRST+27 -#define IDS_FACT IDS_FNSZFIRST+28 -#define IDS_REC IDS_FNSZFIRST+29 -#define IDS_DEGREES IDS_FNSZFIRST+30 -#define IDS_NEGATE IDS_FNSZFIRST+31 -#define IDS_RSH IDS_FNSZFIRST+32 - -#define IDS_FNSZLAST IDS_RSH - -#define IDS_ERRORS_FIRST IDS_FNSZLAST+1 +inline constexpr auto IDS_ERRORS_FIRST = 99; // This is the list of error strings corresponding to SCERR_DIVIDEZERO.. -#define IDS_DIVBYZERO IDS_ERRORS_FIRST -#define IDS_DOMAIN IDS_ERRORS_FIRST+1 -#define IDS_UNDEFINED IDS_ERRORS_FIRST+2 -#define IDS_POS_INFINITY IDS_ERRORS_FIRST+3 -#define IDS_NEG_INFINITY IDS_ERRORS_FIRST+4 -#define IDS_NOMEM IDS_ERRORS_FIRST+6 -#define IDS_TOOMANY IDS_ERRORS_FIRST+7 -#define IDS_OVERFLOW IDS_ERRORS_FIRST+8 -#define IDS_NORESULT IDS_ERRORS_FIRST+9 -#define IDS_INSUFFICIENT_DATA IDS_ERRORS_FIRST+10 +inline constexpr auto IDS_DIVBYZERO = IDS_ERRORS_FIRST; +inline constexpr auto IDS_DOMAIN = IDS_ERRORS_FIRST + 1; +inline constexpr auto IDS_UNDEFINED = IDS_ERRORS_FIRST + 2; +inline constexpr auto IDS_POS_INFINITY = IDS_ERRORS_FIRST + 3; +inline constexpr auto IDS_NEG_INFINITY = IDS_ERRORS_FIRST + 4; +inline constexpr auto IDS_NOMEM = IDS_ERRORS_FIRST + 6; +inline constexpr auto IDS_TOOMANY = IDS_ERRORS_FIRST + 7; +inline constexpr auto IDS_OVERFLOW = IDS_ERRORS_FIRST + 8; +inline constexpr auto IDS_NORESULT = IDS_ERRORS_FIRST + 9; +inline constexpr auto IDS_INSUFFICIENT_DATA = IDS_ERRORS_FIRST + 10; -#define CSTRINGSENGMAX IDS_INSUFFICIENT_DATA+1 +inline constexpr auto CSTRINGSENGMAX = IDS_INSUFFICIENT_DATA + 1; // Arithmetic expression evaluator error strings -#define IDS_ERR_UNK_CH CSTRINGSENGMAX+1 -#define IDS_ERR_UNK_FN CSTRINGSENGMAX+2 -#define IDS_ERR_UNEX_NUM CSTRINGSENGMAX+3 -#define IDS_ERR_UNEX_CH CSTRINGSENGMAX+4 -#define IDS_ERR_UNEX_SZ CSTRINGSENGMAX+5 -#define IDS_ERR_MISMATCH_CLOSE CSTRINGSENGMAX+6 -#define IDS_ERR_UNEX_END CSTRINGSENGMAX+7 -#define IDS_ERR_SG_INV_ERROR CSTRINGSENGMAX+8 -#define IDS_ERR_INPUT_OVERFLOW CSTRINGSENGMAX+9 -#define IDS_ERR_OUTPUT_OVERFLOW CSTRINGSENGMAX+10 +inline constexpr auto IDS_ERR_UNK_CH = CSTRINGSENGMAX + 1; +inline constexpr auto IDS_ERR_UNK_FN = CSTRINGSENGMAX + 2; +inline constexpr auto IDS_ERR_UNEX_NUM = CSTRINGSENGMAX + 3; +inline constexpr auto IDS_ERR_UNEX_CH = CSTRINGSENGMAX + 4; +inline constexpr auto IDS_ERR_UNEX_SZ = CSTRINGSENGMAX + 5; +inline constexpr auto IDS_ERR_MISMATCH_CLOSE = CSTRINGSENGMAX + 6; +inline constexpr auto IDS_ERR_UNEX_END = CSTRINGSENGMAX + 7; +inline constexpr auto IDS_ERR_SG_INV_ERROR = CSTRINGSENGMAX + 8; +inline constexpr auto IDS_ERR_INPUT_OVERFLOW = CSTRINGSENGMAX + 9; +inline constexpr auto IDS_ERR_OUTPUT_OVERFLOW = CSTRINGSENGMAX + 10; - -#define SIDS_PLUS_MINUS L"0" -#define SIDS_CLEAR L"1" -#define SIDS_CE L"2" -#define SIDS_BACKSPACE L"3" -#define SIDS_DECIMAL_SEPARATOR L"4" -#define SIDS_EMPTY_STRING L"5" -#define SIDS_AND L"6" -#define SIDS_OR L"7" -#define SIDS_XOR L"8" -#define SIDS_LSH L"9" -#define SIDS_RSH L"10" -#define SIDS_DIVIDE L"11" -#define SIDS_MULTIPLY L"12" -#define SIDS_PLUS L"13" -#define SIDS_MINUS L"14" -#define SIDS_MOD L"15" -#define SIDS_YROOT L"16" -#define SIDS_POW_HAT L"17" -#define SIDS_INT L"18" -#define SIDS_ROL L"19" -#define SIDS_ROR L"20" -#define SIDS_NOT L"21" -#define SIDS_SIN L"22" -#define SIDS_COS L"23" -#define SIDS_TAN L"24" -#define SIDS_SINH L"25" -#define SIDS_COSH L"26" -#define SIDS_TANH L"27" -#define SIDS_LN L"28" -#define SIDS_LOG L"29" -#define SIDS_SQRT L"30" -#define SIDS_XPOW2 L"31" -#define SIDS_XPOW3 L"32" -#define SIDS_NFACTORIAL L"33" -#define SIDS_RECIPROCAL L"34" -#define SIDS_DMS L"35" -#define SIDS_CUBEROOT L"36" -#define SIDS_POWTEN L"37" -#define SIDS_PERCENT L"38" -#define SIDS_SCIENTIFIC_NOTATION L"39" -#define SIDS_PI L"40" -#define SIDS_EQUAL L"41" -#define SIDS_MC L"42" -#define SIDS_MR L"43" -#define SIDS_MS L"44" -#define SIDS_MPLUS L"45" -#define SIDS_MMINUS L"46" -#define SIDS_EXP L"47" -#define SIDS_OPEN_PAREN L"48" -#define SIDS_CLOSE_PAREN L"49" -#define SIDS_0 L"50" -#define SIDS_1 L"51" -#define SIDS_2 L"52" -#define SIDS_3 L"53" -#define SIDS_4 L"54" -#define SIDS_5 L"55" -#define SIDS_6 L"56" -#define SIDS_7 L"57" -#define SIDS_8 L"58" -#define SIDS_9 L"59" -#define SIDS_A L"60" -#define SIDS_B L"61" -#define SIDS_C L"62" -#define SIDS_D L"63" -#define SIDS_E L"64" -#define SIDS_F L"65" -#define SIDS_FRAC L"66" -#define SIDS_SIND L"67" -#define SIDS_COSD L"68" -#define SIDS_TAND L"69" -#define SIDS_ASIND L"70" -#define SIDS_ACOSD L"71" -#define SIDS_ATAND L"72" -#define SIDS_SINR L"73" -#define SIDS_COSR L"74" -#define SIDS_TANR L"75" -#define SIDS_ASINR L"76" -#define SIDS_ACOSR L"77" -#define SIDS_ATANR L"78" -#define SIDS_SING L"79" -#define SIDS_COSG L"80" -#define SIDS_TANG L"81" -#define SIDS_ASING L"82" -#define SIDS_ACOSG L"83" -#define SIDS_ATANG L"84" -#define SIDS_ASINH L"85" -#define SIDS_ACOSH L"86" -#define SIDS_ATANH L"87" -#define SIDS_POWE L"88" -#define SIDS_POWTEN2 L"89" -#define SIDS_SQRT2 L"90" -#define SIDS_SQR L"91" -#define SIDS_CUBE L"92" -#define SIDS_CUBERT L"93" -#define SIDS_FACT L"94" -#define SIDS_RECIPROC L"95" -#define SIDS_DEGREES L"96" -#define SIDS_NEGATE L"97" -#define SIDS_RSH2 L"98" -#define SIDS_DIVIDEBYZERO L"99" -#define SIDS_DOMAIN L"100" -#define SIDS_UNDEFINED L"101" -#define SIDS_POS_INFINITY L"102" -#define SIDS_NEG_INFINITY L"103" -#define SIDS_ABORTED L"104" -#define SIDS_NOMEM L"105" -#define SIDS_TOOMANY L"106" -#define SIDS_OVERFLOW L"107" -#define SIDS_NORESULT L"108" -#define SIDS_INSUFFICIENT_DATA L"109" +// Resource keys for CEngineStrings.resw +inline constexpr auto SIDS_PLUS_MINUS = L"0"; +inline constexpr auto SIDS_CLEAR = L"1"; +inline constexpr auto SIDS_CE = L"2"; +inline constexpr auto SIDS_BACKSPACE = L"3"; +inline constexpr auto SIDS_DECIMAL_SEPARATOR = L"4"; +inline constexpr auto SIDS_EMPTY_STRING = L"5"; +inline constexpr auto SIDS_AND = L"6"; +inline constexpr auto SIDS_OR = L"7"; +inline constexpr auto SIDS_XOR = L"8"; +inline constexpr auto SIDS_LSH = L"9"; +inline constexpr auto SIDS_RSH = L"10"; +inline constexpr auto SIDS_DIVIDE = L"11"; +inline constexpr auto SIDS_MULTIPLY = L"12"; +inline constexpr auto SIDS_PLUS = L"13"; +inline constexpr auto SIDS_MINUS = L"14"; +inline constexpr auto SIDS_MOD = L"15"; +inline constexpr auto SIDS_YROOT = L"16"; +inline constexpr auto SIDS_POW_HAT = L"17"; +inline constexpr auto SIDS_INT = L"18"; +inline constexpr auto SIDS_ROL = L"19"; +inline constexpr auto SIDS_ROR = L"20"; +inline constexpr auto SIDS_NOT = L"21"; +inline constexpr auto SIDS_SIN = L"22"; +inline constexpr auto SIDS_COS = L"23"; +inline constexpr auto SIDS_TAN = L"24"; +inline constexpr auto SIDS_SINH = L"25"; +inline constexpr auto SIDS_COSH = L"26"; +inline constexpr auto SIDS_TANH = L"27"; +inline constexpr auto SIDS_LN = L"28"; +inline constexpr auto SIDS_LOG = L"29"; +inline constexpr auto SIDS_SQRT = L"30"; +inline constexpr auto SIDS_XPOW2 = L"31"; +inline constexpr auto SIDS_XPOW3 = L"32"; +inline constexpr auto SIDS_NFACTORIAL = L"33"; +inline constexpr auto SIDS_RECIPROCAL = L"34"; +inline constexpr auto SIDS_DMS = L"35"; +inline constexpr auto SIDS_CUBEROOT = L"36"; +inline constexpr auto SIDS_POWTEN = L"37"; +inline constexpr auto SIDS_PERCENT = L"38"; +inline constexpr auto SIDS_SCIENTIFIC_NOTATION = L"39"; +inline constexpr auto SIDS_PI = L"40"; +inline constexpr auto SIDS_EQUAL = L"41"; +inline constexpr auto SIDS_MC = L"42"; +inline constexpr auto SIDS_MR = L"43"; +inline constexpr auto SIDS_MS = L"44"; +inline constexpr auto SIDS_MPLUS = L"45"; +inline constexpr auto SIDS_MMINUS = L"46"; +inline constexpr auto SIDS_EXP = L"47"; +inline constexpr auto SIDS_OPEN_PAREN = L"48"; +inline constexpr auto SIDS_CLOSE_PAREN = L"49"; +inline constexpr auto SIDS_0 = L"50"; +inline constexpr auto SIDS_1 = L"51"; +inline constexpr auto SIDS_2 = L"52"; +inline constexpr auto SIDS_3 = L"53"; +inline constexpr auto SIDS_4 = L"54"; +inline constexpr auto SIDS_5 = L"55"; +inline constexpr auto SIDS_6 = L"56"; +inline constexpr auto SIDS_7 = L"57"; +inline constexpr auto SIDS_8 = L"58"; +inline constexpr auto SIDS_9 = L"59"; +inline constexpr auto SIDS_A = L"60"; +inline constexpr auto SIDS_B = L"61"; +inline constexpr auto SIDS_C = L"62"; +inline constexpr auto SIDS_D = L"63"; +inline constexpr auto SIDS_E = L"64"; +inline constexpr auto SIDS_F = L"65"; +inline constexpr auto SIDS_FRAC = L"66"; +inline constexpr auto SIDS_SIND = L"67"; +inline constexpr auto SIDS_COSD = L"68"; +inline constexpr auto SIDS_TAND = L"69"; +inline constexpr auto SIDS_ASIND = L"70"; +inline constexpr auto SIDS_ACOSD = L"71"; +inline constexpr auto SIDS_ATAND = L"72"; +inline constexpr auto SIDS_SINR = L"73"; +inline constexpr auto SIDS_COSR = L"74"; +inline constexpr auto SIDS_TANR = L"75"; +inline constexpr auto SIDS_ASINR = L"76"; +inline constexpr auto SIDS_ACOSR = L"77"; +inline constexpr auto SIDS_ATANR = L"78"; +inline constexpr auto SIDS_SING = L"79"; +inline constexpr auto SIDS_COSG = L"80"; +inline constexpr auto SIDS_TANG = L"81"; +inline constexpr auto SIDS_ASING = L"82"; +inline constexpr auto SIDS_ACOSG = L"83"; +inline constexpr auto SIDS_ATANG = L"84"; +inline constexpr auto SIDS_ASINH = L"85"; +inline constexpr auto SIDS_ACOSH = L"86"; +inline constexpr auto SIDS_ATANH = L"87"; +inline constexpr auto SIDS_POWE = L"88"; +inline constexpr auto SIDS_POWTEN2 = L"89"; +inline constexpr auto SIDS_SQRT2 = L"90"; +inline constexpr auto SIDS_SQR = L"91"; +inline constexpr auto SIDS_CUBE = L"92"; +inline constexpr auto SIDS_CUBERT = L"93"; +inline constexpr auto SIDS_FACT = L"94"; +inline constexpr auto SIDS_RECIPROC = L"95"; +inline constexpr auto SIDS_DEGREES = L"96"; +inline constexpr auto SIDS_NEGATE = L"97"; +inline constexpr auto SIDS_RSH2 = L"98"; +inline constexpr auto SIDS_DIVIDEBYZERO = L"99"; +inline constexpr auto SIDS_DOMAIN = L"100"; +inline constexpr auto SIDS_UNDEFINED = L"101"; +inline constexpr auto SIDS_POS_INFINITY = L"102"; +inline constexpr auto SIDS_NEG_INFINITY = L"103"; +inline constexpr auto SIDS_ABORTED = L"104"; +inline constexpr auto SIDS_NOMEM = L"105"; +inline constexpr auto SIDS_TOOMANY = L"106"; +inline constexpr auto SIDS_OVERFLOW = L"107"; +inline constexpr auto SIDS_NORESULT = L"108"; +inline constexpr auto SIDS_INSUFFICIENT_DATA = L"109"; // 110 is skipped by CSTRINGSENGMAX -#define SIDS_ERR_UNK_CH L"111" -#define SIDS_ERR_UNK_FN L"112" -#define SIDS_ERR_UNEX_NUM L"113" -#define SIDS_ERR_UNEX_CH L"114" -#define SIDS_ERR_UNEX_SZ L"115" -#define SIDS_ERR_MISMATCH_CLOSE L"116" -#define SIDS_ERR_UNEX_END L"117" -#define SIDS_ERR_SG_INV_ERROR L"118" -#define SIDS_ERR_INPUT_OVERFLOW L"119" -#define SIDS_ERR_OUTPUT_OVERFLOW L"120" +inline constexpr auto SIDS_ERR_UNK_CH = L"111"; +inline constexpr auto SIDS_ERR_UNK_FN = L"112"; +inline constexpr auto SIDS_ERR_UNEX_NUM = L"113"; +inline constexpr auto SIDS_ERR_UNEX_CH = L"114"; +inline constexpr auto SIDS_ERR_UNEX_SZ = L"115"; +inline constexpr auto SIDS_ERR_MISMATCH_CLOSE = L"116"; +inline constexpr auto SIDS_ERR_UNEX_END = L"117"; +inline constexpr auto SIDS_ERR_SG_INV_ERROR = L"118"; +inline constexpr auto SIDS_ERR_INPUT_OVERFLOW = L"119"; +inline constexpr auto SIDS_ERR_OUTPUT_OVERFLOW = L"120"; -__declspec(selectany) std::wstring g_sids[] = +// Include the resource key ID from above into this vector to load it into memory for the engine to use +inline constexpr std::array g_sids = { - std::wstring(SIDS_PLUS_MINUS), - std::wstring(SIDS_C), - std::wstring(SIDS_CE), - std::wstring(SIDS_BACKSPACE), - std::wstring(SIDS_DECIMAL_SEPARATOR), - std::wstring(SIDS_EMPTY_STRING), - std::wstring(SIDS_AND), - std::wstring(SIDS_OR), - std::wstring(SIDS_XOR), - std::wstring(SIDS_LSH), - std::wstring(SIDS_RSH), - std::wstring(SIDS_DIVIDE), - std::wstring(SIDS_MULTIPLY), - std::wstring(SIDS_PLUS), - std::wstring(SIDS_MINUS), - std::wstring(SIDS_MOD), - std::wstring(SIDS_YROOT), - std::wstring(SIDS_POW_HAT), - std::wstring(SIDS_INT), - std::wstring(SIDS_ROL), - std::wstring(SIDS_ROR), - std::wstring(SIDS_NOT), - std::wstring(SIDS_SIN), - std::wstring(SIDS_COS), - std::wstring(SIDS_TAN), - std::wstring(SIDS_SINH), - std::wstring(SIDS_COSH), - std::wstring(SIDS_TANH), - std::wstring(SIDS_LN), - std::wstring(SIDS_LOG), - std::wstring(SIDS_SQRT), - std::wstring(SIDS_XPOW2), - std::wstring(SIDS_XPOW3), - std::wstring(SIDS_NFACTORIAL), - std::wstring(SIDS_RECIPROCAL), - std::wstring(SIDS_DMS), - std::wstring(SIDS_CUBEROOT), - std::wstring(SIDS_POWTEN), - std::wstring(SIDS_PERCENT), - std::wstring(SIDS_SCIENTIFIC_NOTATION), - std::wstring(SIDS_PI), - std::wstring(SIDS_EQUAL), - std::wstring(SIDS_MC), - std::wstring(SIDS_MR), - std::wstring(SIDS_MS), - std::wstring(SIDS_MPLUS), - std::wstring(SIDS_MMINUS), - std::wstring(SIDS_EXP), - std::wstring(SIDS_OPEN_PAREN), - std::wstring(SIDS_CLOSE_PAREN), - std::wstring(SIDS_0), - std::wstring(SIDS_1), - std::wstring(SIDS_2), - std::wstring(SIDS_3), - std::wstring(SIDS_4), - std::wstring(SIDS_5), - std::wstring(SIDS_6), - std::wstring(SIDS_7), - std::wstring(SIDS_8), - std::wstring(SIDS_9), - std::wstring(SIDS_A), - std::wstring(SIDS_B), - std::wstring(SIDS_C), - std::wstring(SIDS_D), - std::wstring(SIDS_E), - std::wstring(SIDS_F), - std::wstring(SIDS_FRAC), - std::wstring(SIDS_SIND), - std::wstring(SIDS_COSD), - std::wstring(SIDS_TAND), - std::wstring(SIDS_ASIND), - std::wstring(SIDS_ACOSD), - std::wstring(SIDS_ATAND), - std::wstring(SIDS_SINR), - std::wstring(SIDS_COSR), - std::wstring(SIDS_TANR), - std::wstring(SIDS_ASINR), - std::wstring(SIDS_ACOSR), - std::wstring(SIDS_ATANR), - std::wstring(SIDS_SING), - std::wstring(SIDS_COSG), - std::wstring(SIDS_TANG), - std::wstring(SIDS_ASING), - std::wstring(SIDS_ACOSG), - std::wstring(SIDS_ATANG), - std::wstring(SIDS_ASINH), - std::wstring(SIDS_ACOSH), - std::wstring(SIDS_ATANH), - std::wstring(SIDS_POWE), - std::wstring(SIDS_POWTEN2), - std::wstring(SIDS_SQRT2), - std::wstring(SIDS_SQR), - std::wstring(SIDS_CUBE), - std::wstring(SIDS_CUBERT), - std::wstring(SIDS_FACT), - std::wstring(SIDS_RECIPROC), - std::wstring(SIDS_DEGREES), - std::wstring(SIDS_NEGATE), - std::wstring(SIDS_RSH), - std::wstring(SIDS_DIVIDEBYZERO), - std::wstring(SIDS_DOMAIN), - std::wstring(SIDS_UNDEFINED), - std::wstring(SIDS_POS_INFINITY), - std::wstring(SIDS_NEG_INFINITY), - std::wstring(SIDS_ABORTED), - std::wstring(SIDS_NOMEM), - std::wstring(SIDS_TOOMANY), - std::wstring(SIDS_OVERFLOW), - std::wstring(SIDS_NORESULT), - std::wstring(SIDS_INSUFFICIENT_DATA), - std::wstring(SIDS_ERR_UNK_CH), - std::wstring(SIDS_ERR_UNK_FN), - std::wstring(SIDS_ERR_UNEX_NUM), - std::wstring(SIDS_ERR_UNEX_CH), - std::wstring(SIDS_ERR_UNEX_SZ), - std::wstring(SIDS_ERR_MISMATCH_CLOSE), - std::wstring(SIDS_ERR_UNEX_END), - std::wstring(SIDS_ERR_SG_INV_ERROR), - std::wstring(SIDS_ERR_INPUT_OVERFLOW), - std::wstring(SIDS_ERR_OUTPUT_OVERFLOW) + SIDS_PLUS_MINUS, + SIDS_C, + SIDS_CE, + SIDS_BACKSPACE, + SIDS_DECIMAL_SEPARATOR, + SIDS_EMPTY_STRING, + SIDS_AND, + SIDS_OR, + SIDS_XOR, + SIDS_LSH, + SIDS_RSH, + SIDS_DIVIDE, + SIDS_MULTIPLY, + SIDS_PLUS, + SIDS_MINUS, + SIDS_MOD, + SIDS_YROOT, + SIDS_POW_HAT, + SIDS_INT, + SIDS_ROL, + SIDS_ROR, + SIDS_NOT, + SIDS_SIN, + SIDS_COS, + SIDS_TAN, + SIDS_SINH, + SIDS_COSH, + SIDS_TANH, + SIDS_LN, + SIDS_LOG, + SIDS_SQRT, + SIDS_XPOW2, + SIDS_XPOW3, + SIDS_NFACTORIAL, + SIDS_RECIPROCAL, + SIDS_DMS, + SIDS_CUBEROOT, + SIDS_POWTEN, + SIDS_PERCENT, + SIDS_SCIENTIFIC_NOTATION, + SIDS_PI, + SIDS_EQUAL, + SIDS_MC, + SIDS_MR, + SIDS_MS, + SIDS_MPLUS, + SIDS_MMINUS, + SIDS_EXP, + SIDS_OPEN_PAREN, + SIDS_CLOSE_PAREN, + SIDS_0, + SIDS_1, + SIDS_2, + SIDS_3, + SIDS_4, + SIDS_5, + SIDS_6, + SIDS_7, + SIDS_8, + SIDS_9, + SIDS_A, + SIDS_B, + SIDS_C, + SIDS_D, + SIDS_E, + SIDS_F, + SIDS_FRAC, + SIDS_SIND, + SIDS_COSD, + SIDS_TAND, + SIDS_ASIND, + SIDS_ACOSD, + SIDS_ATAND, + SIDS_SINR, + SIDS_COSR, + SIDS_TANR, + SIDS_ASINR, + SIDS_ACOSR, + SIDS_ATANR, + SIDS_SING, + SIDS_COSG, + SIDS_TANG, + SIDS_ASING, + SIDS_ACOSG, + SIDS_ATANG, + SIDS_ASINH, + SIDS_ACOSH, + SIDS_ATANH, + SIDS_POWE, + SIDS_POWTEN2, + SIDS_SQRT2, + SIDS_SQR, + SIDS_CUBE, + SIDS_CUBERT, + SIDS_FACT, + SIDS_RECIPROC, + SIDS_DEGREES, + SIDS_NEGATE, + SIDS_RSH, + SIDS_DIVIDEBYZERO, + SIDS_DOMAIN, + SIDS_UNDEFINED, + SIDS_POS_INFINITY, + SIDS_NEG_INFINITY, + SIDS_ABORTED, + SIDS_NOMEM, + SIDS_TOOMANY, + SIDS_OVERFLOW, + SIDS_NORESULT, + SIDS_INSUFFICIENT_DATA, + SIDS_ERR_UNK_CH, + SIDS_ERR_UNK_FN, + SIDS_ERR_UNEX_NUM, + SIDS_ERR_UNEX_CH, + SIDS_ERR_UNEX_SZ, + SIDS_ERR_MISMATCH_CLOSE, + SIDS_ERR_UNEX_END, + SIDS_ERR_SG_INV_ERROR, + SIDS_ERR_INPUT_OVERFLOW, + SIDS_ERR_OUTPUT_OVERFLOW }; diff --git a/src/CalcManager/Header Files/History.h b/src/CalcManager/Header Files/History.h index 4f82088f..7446616d 100644 --- a/src/CalcManager/Header Files/History.h +++ b/src/CalcManager/Header Files/History.h @@ -3,6 +3,7 @@ #pragma once +#include #include "ICalcDisplay.h" #include "IHistoryDisplay.h" #include "Rational.h" diff --git a/src/CalcManager/Header Files/ICalcDisplay.h b/src/CalcManager/Header Files/ICalcDisplay.h index 2ba57e65..73fce932 100644 --- a/src/CalcManager/Header Files/ICalcDisplay.h +++ b/src/CalcManager/Header Files/ICalcDisplay.h @@ -12,7 +12,7 @@ public: virtual void SetPrimaryDisplay(const std::wstring& pszText, bool isError) = 0; virtual void SetIsInError(bool isInError) = 0; virtual void SetExpressionDisplay(_Inout_ std::shared_ptr>> const &tokens, _Inout_ std::shared_ptr>> const &commands) = 0; - virtual void SetParenDisplayText(const std::wstring& pszText) = 0; + virtual void SetParenthesisNumber(_In_ unsigned int count) = 0; virtual void OnNoRightParenAdded() = 0; virtual void MaxDigitsReached() = 0; // not an error but still need to inform UI layer. virtual void BinaryOperatorReceived() = 0; diff --git a/src/CalcManager/Header Files/Number.h b/src/CalcManager/Header Files/Number.h index c67aa108..769e3acf 100644 --- a/src/CalcManager/Header Files/Number.h +++ b/src/CalcManager/Header Files/Number.h @@ -3,6 +3,7 @@ #pragma once +#include #include "Ratpack/ratpak.h" namespace CalcEngine diff --git a/src/CalcManager/Header Files/RationalMath.h b/src/CalcManager/Header Files/RationalMath.h index b52c1c5f..59500573 100644 --- a/src/CalcManager/Header Files/RationalMath.h +++ b/src/CalcManager/Header Files/RationalMath.h @@ -13,6 +13,7 @@ namespace CalcEngine::RationalMath Rational Pow(Rational const& base, Rational const& pow); Rational Root(Rational const& base, Rational const& root); Rational Fact(Rational const& rat); + Rational Mod(Rational const& a, Rational const& b); Rational Exp(Rational const& rat); Rational Log(Rational const& rat); diff --git a/src/CalcManager/Ratpack/CalcErr.h b/src/CalcManager/Ratpack/CalcErr.h index b420a766..8c23e440 100644 --- a/src/CalcManager/Ratpack/CalcErr.h +++ b/src/CalcManager/Ratpack/CalcErr.h @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +#pragma once + // CalcErr.h // // Defines the error codes thrown by ratpak and caught by Calculator @@ -24,7 +26,7 @@ // R - Reserved - not currently used for anything // // r - reserved portion of the facility code. Reserved for internal -// use. Used to indicate HRESULT values that are not status +// use. Used to indicate int32_t values that are not status // values, but are instead message ids for display strings. // // Facility - is the facility code @@ -34,49 +36,51 @@ // This format is based loosely on an OLE HRESULT and is compatible with the // SUCCEEDED and FAILED macros as well as the HRESULT_CODE macro +typedef int32_t ResultCode; + // CALC_E_DIVIDEBYZERO // // The current operation would require a divide by zero to complete -#define CALC_E_DIVIDEBYZERO ((DWORD)0x80000000) +#define CALC_E_DIVIDEBYZERO ((uint32_t)0x80000000) // CALC_E_DOMAIN // // The given input is not within the domain of this function -#define CALC_E_DOMAIN ((DWORD)0x80000001) +#define CALC_E_DOMAIN ((uint32_t)0x80000001) // CALC_E_INDEFINITE // // The result of this function is undefined -#define CALC_E_INDEFINITE ((DWORD)0x80000002) +#define CALC_E_INDEFINITE ((uint32_t)0x80000002) // CALC_E_POSINFINITY // // The result of this function is Positive Infinity. -#define CALC_E_POSINFINITY ((DWORD)0x80000003) +#define CALC_E_POSINFINITY ((uint32_t)0x80000003) // CALC_E_NEGINFINITY // // The result of this function is Negative Infinity -#define CALC_E_NEGINFINITY ((DWORD)0x80000004) +#define CALC_E_NEGINFINITY ((uint32_t)0x80000004) // CALC_E_INVALIDRANGE // // The given input is within the domain of the function but is beyond // the range for which calc can successfully compute the answer -#define CALC_E_INVALIDRANGE ((DWORD)0x80000006) +#define CALC_E_INVALIDRANGE ((uint32_t)0x80000006) // CALC_E_OUTOFMEMORY // // There is not enough free memory to complete the requested function -#define CALC_E_OUTOFMEMORY ((DWORD)0x80000007) +#define CALC_E_OUTOFMEMORY ((uint32_t)0x80000007) // CALC_E_OVERFLOW // // The result of this operation is an overflow -#define CALC_E_OVERFLOW ((DWORD)0x80000008) +#define CALC_E_OVERFLOW ((uint32_t)0x80000008) // CALC_E_NORESULT // // The result of this operation is undefined -#define CALC_E_NORESULT ((DWORD)0x80000009) +#define CALC_E_NORESULT ((uint32_t)0x80000009) diff --git a/src/CalcManager/Ratpack/basex.cpp b/src/CalcManager/Ratpack/basex.cpp index 1d4a7303..2685af87 100644 --- a/src/CalcManager/Ratpack/basex.cpp +++ b/src/CalcManager/Ratpack/basex.cpp @@ -14,8 +14,8 @@ // internal base is a power of 2. // //----------------------------------------------------------------------------- -#include "pch.h" #include "ratpak.h" +#include // for memmove void _mulnumx( PNUMBER *pa, PNUMBER b ); @@ -48,7 +48,7 @@ void __inline mulnumx( PNUMBER *pa, PNUMBER b ) else { // if pa is one and b isn't just copy b. and adjust the sign. - long sign = (*pa)->sign; + int32_t sign = (*pa)->sign; DUPNUM(*pa,b); (*pa)->sign *= sign; } @@ -86,14 +86,14 @@ void _mulnumx( PNUMBER *pa, PNUMBER b ) MANTTYPE *ptrc; // ptrc is a pointer to the mantissa of c. MANTTYPE *ptrcoffset; // ptrcoffset, is the anchor location of the next // single digit multiply partial result. - long iadigit=0; // Index of digit being used in the first number. - long ibdigit=0; // Index of digit being used in the second number. + int32_t iadigit=0; // Index of digit being used in the first number. + int32_t ibdigit=0; // Index of digit being used in the second number. MANTTYPE da=0; // da is the digit from the fist number. TWO_MANTTYPE cy=0; // cy is the carry resulting from the addition of // a multiplied row into the result. TWO_MANTTYPE mcy=0; // mcy is the resultant from a single // multiply, AND the carry of that multiply. - long icdigit=0; // Index of digit being calculated in final result. + int32_t icdigit=0; // Index of digit being calculated in final result. a=*pa; @@ -117,7 +117,7 @@ void _mulnumx( PNUMBER *pa, PNUMBER b ) for ( ibdigit = b->cdigit; ibdigit > 0; ibdigit-- ) { cy = 0; - mcy = (DWORDLONG)da * (*ptrb); + mcy = (uint64_t)da * (*ptrb); if ( mcy ) { icdigit = 0; @@ -132,10 +132,10 @@ void _mulnumx( PNUMBER *pa, PNUMBER b ) { // update carry from addition(s) and multiply. - cy += (TWO_MANTTYPE)ptrc[icdigit]+((DWORD)mcy&((DWORD)~BASEX)); + cy += (TWO_MANTTYPE)ptrc[icdigit]+((uint32_t)mcy&((uint32_t)~BASEX)); // update result digit from - ptrc[icdigit++]=(MANTTYPE)((DWORD)cy&((DWORD)~BASEX)); + ptrc[icdigit++]=(MANTTYPE)((uint32_t)cy&((uint32_t)~BASEX)); // update carries from mcy >>= BASEXPWR; @@ -160,9 +160,9 @@ void _mulnumx( PNUMBER *pa, PNUMBER b ) } //----------------------------------------------------------------------------- // -// FUNCTION: numpowlongx +// FUNCTION: numpowi32x // -// ARGUMENTS: root as number power as long +// ARGUMENTS: root as number power as int32_t // number. // // RETURN: None root is changed. @@ -174,10 +174,10 @@ void _mulnumx( PNUMBER *pa, PNUMBER b ) // //----------------------------------------------------------------------------- -void numpowlongx( _Inout_ PNUMBER *proot, _In_ long power ) +void numpowi32x( _Inout_ PNUMBER *proot, _In_ int32_t power ) { - PNUMBER lret = longtonum( 1, BASEX ); + PNUMBER lret = i32tonum( 1, BASEX ); // Once the power remaining is zero we are done. while ( power > 0 ) @@ -232,7 +232,7 @@ void __inline divnumx( PNUMBER *pa, PNUMBER b, int32_t precision) else { // if pa is one and b is not one, just copy b, and adjust the sign. - long sign = (*pa)->sign; + int32_t sign = (*pa)->sign; DUPNUM(*pa,b); (*pa)->sign *= sign; } @@ -266,10 +266,10 @@ void _divnumx( PNUMBER *pa, PNUMBER b, int32_t precision) // guesses one bit too far. PNUMBER tmp = nullptr; // current guess being worked on for divide. PNUMBER rem = nullptr; // remainder after applying guess. - long cdigits; // count of digits for answer. + int32_t cdigits; // count of digits for answer. MANTTYPE *ptrc; // ptrc is a pointer to the mantissa of c. - long thismax = precision + g_ratio; // set a maximum number of internal digits + int32_t thismax = precision + g_ratio; // set a maximum number of internal digits // to shoot for in the divide. a=*pa; @@ -301,14 +301,14 @@ void _divnumx( PNUMBER *pa, PNUMBER b, int32_t precision) while ( cdigits++ < thismax && !zernum(rem) ) { - long digit = 0; + int32_t digit = 0; *ptrc = 0; while ( !lessnum( rem, b ) ) { digit = 1; DUPNUM( tmp, b ); destroynum( lasttmp ); - lasttmp=longtonum( 0, BASEX ); + lasttmp=i32tonum( 0, BASEX ); while ( lessnum( tmp, rem ) ) { destroynum( lasttmp ); diff --git a/src/CalcManager/Ratpack/conv.cpp b/src/CalcManager/Ratpack/conv.cpp index cfd2ec40..3a1aaa14 100644 --- a/src/CalcManager/Ratpack/conv.cpp +++ b/src/CalcManager/Ratpack/conv.cpp @@ -11,13 +11,16 @@ // Description // // Contains conversion, input and output routines for numbers rationals -// and longs. +// and i32s. // // // //--------------------------------------------------------------------------- -#include "pch.h" +#include +#include +#include +#include // for memmove, memcpy #include "ratpak.h" using namespace std; @@ -29,12 +32,87 @@ static constexpr wstring_view DIGITS = L"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabc // ratio of internal 'digits' to output 'digits' // Calculated elsewhere as part of initialization and when base is changed -long g_ratio; // int(log(2L^BASEXPWR)/log(radix)) +int32_t g_ratio; // int(log(2L^BASEXPWR)/log(radix)) // Default decimal separator wchar_t g_decimalSeparator = L'.'; +// The following defines and Calc_ULong* functions were taken from +// https://github.com/dotnet/coreclr/blob/8b1595b74c943b33fa794e63e440e6f4c9679478/src/pal/inc/rt/intsafe.h +// under MIT License +// See also +// * https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros +// * https://sourceforge.net/p/predef/wiki/Architectures/ +#if defined(MIDL_PASS) || defined(RC_INVOKED) || defined(_M_CEE_PURE) \ + || defined(_M_AMD64) || defined(__ARM_ARCH) || defined(__x86_64__) || defined(_M_ARM64) + +#ifndef Calc_UInt32x32To64 +#define Calc_UInt32x32To64(a, b) ((uint64_t)((uint32_t)(a)) * (uint64_t)((uint32_t)(b))) +#endif + +#elif defined(_M_IX86) || defined(__i386__) || defined(_M_ARM) + +#ifndef Calc_UInt32x32To64 +#define Calc_UInt32x32To64(a, b) (uint64_t)((uint64_t)(uint32_t)(a) * (uint32_t)(b)) +#endif +#else + +#error Must define a target architecture. + +#endif + +#define CALC_INTSAFE_E_ARITHMETIC_OVERFLOW ((int32_t)0x80070216L) // 0x216 = 534 = ERROR_ARITHMETIC_OVERFLOW +#define CALC_ULONG_ERROR ((uint32_t)0xffffffffU) + +namespace { + int32_t + Calc_ULongAdd( + _In_ uint32_t ulAugend, + _In_ uint32_t ulAddend, + _Out_ uint32_t* pulResult) + { + int32_t hr = CALC_INTSAFE_E_ARITHMETIC_OVERFLOW; + *pulResult = CALC_ULONG_ERROR; + + if ((ulAugend + ulAddend) >= ulAugend) + { + *pulResult = (ulAugend + ulAddend); + hr = S_OK; + } + + return hr; + } + + int32_t + Calc_ULongLongToULong( + _In_ uint64_t ullOperand, + _Out_ uint32_t* pulResult) + { + int32_t hr = CALC_INTSAFE_E_ARITHMETIC_OVERFLOW; + *pulResult = CALC_ULONG_ERROR; + + if (ullOperand <= UINT32_MAX) + { + *pulResult = (uint32_t)ullOperand; + hr = S_OK; + } + + return hr; + } + + int32_t + Calc_ULongMult( + _In_ uint32_t ulMultiplicand, + _In_ uint32_t ulMultiplier, + _Out_ uint32_t* pulResult) + { + uint64_t ull64Result = Calc_UInt32x32To64(ulMultiplicand, ulMultiplier); + + return Calc_ULongLongToULong(ull64Result, pulResult); + } +} + // Used to strip trailing zeros, and prevent combinatorial explosions -bool stripzeroesnum(_Inout_ PNUMBER pnum, long starting); +bool stripzeroesnum(_Inout_ PNUMBER pnum, int32_t starting); void SetDecimalSeparator(wchar_t decimalSeparator) { @@ -125,16 +203,16 @@ void _destroyrat( _In_ PRAT prat ) // //----------------------------------------------------------------------------- -PNUMBER _createnum( _In_ ULONG size ) +PNUMBER _createnum( _In_ uint32_t size ) { PNUMBER pnumret= nullptr; - ULONG cbAlloc; + uint32_t cbAlloc; // sizeof( MANTTYPE ) is the size of a 'digit' - if (SUCCEEDED(ULongAdd(size, 1, &cbAlloc)) && - SUCCEEDED(ULongMult(cbAlloc, sizeof(MANTTYPE), &cbAlloc)) && - SUCCEEDED(ULongAdd(cbAlloc, sizeof(NUMBER), &cbAlloc))) + if (SUCCEEDED(Calc_ULongAdd(size, 1, &cbAlloc)) && + SUCCEEDED(Calc_ULongMult(cbAlloc, sizeof(MANTTYPE), &cbAlloc)) && + SUCCEEDED(Calc_ULongAdd(cbAlloc, sizeof(NUMBER), &cbAlloc))) { pnumret = (PNUMBER)zmalloc( cbAlloc ); if ( pnumret == nullptr) @@ -203,7 +281,7 @@ PRAT numtorat( _In_ PNUMBER pin, uint32_t radix) PNUMBER pnRadixn= nullptr; DUPNUM( pnRadixn, pin ); - PNUMBER qnRadixn=longtonum( 1, radix); + PNUMBER qnRadixn=i32tonum( 1, radix); // Ensure p and q start out as integers. if ( pnRadixn->exp < 0 ) @@ -245,24 +323,24 @@ PRAT numtorat( _In_ PNUMBER pin, uint32_t radix) PNUMBER nRadixxtonum( _In_ PNUMBER a, uint32_t radix, int32_t precision) { - unsigned long bitmask; - unsigned long cdigits; + uint32_t bitmask; + uint32_t cdigits; MANTTYPE *ptr; - PNUMBER sum = longtonum( 0, radix ); - PNUMBER powofnRadix = longtonum( BASEX, radix ); + PNUMBER sum = i32tonum( 0, radix ); + PNUMBER powofnRadix = i32tonum( BASEX, radix ); // A large penalty is paid for conversion of digits no one will see anyway. // limit the digits to the minimum of the existing precision or the // requested precision. cdigits = precision + 1; - if ( cdigits > (unsigned long)a->cdigit ) + if ( cdigits > (uint32_t)a->cdigit ) { - cdigits = (unsigned long)a->cdigit; + cdigits = (uint32_t)a->cdigit; } // scale by the internal base to the internal exponent offset of the LSD - numpowlong( &powofnRadix, a->exp + (a->cdigit - cdigits), radix, precision); + numpowi32( &powofnRadix, a->exp + (a->cdigit - cdigits), radix, precision); // Loop over all the relative digits from MSD to LSD for ( ptr = &(a->mant[a->cdigit-1]); cdigits > 0; @@ -303,8 +381,8 @@ PNUMBER nRadixxtonum( _In_ PNUMBER a, uint32_t radix, int32_t precision) PNUMBER numtonRadixx(_In_ PNUMBER a, uint32_t radix) { - PNUMBER pnumret = longtonum(0, BASEX); // pnumret is the number in internal form. - PNUMBER num_radix = longtonum(radix, BASEX); + PNUMBER pnumret = i32tonum(0, BASEX); // pnumret is the number in internal form. + PNUMBER num_radix = i32tonum(radix, BASEX); MANTTYPE *ptrdigit = a->mant; // pointer to digit being worked on. // Digits are in reverse order, back over them LSD first. @@ -312,20 +390,20 @@ PNUMBER numtonRadixx(_In_ PNUMBER a, uint32_t radix) PNUMBER thisdigit = nullptr; // thisdigit holds the current digit of a // being summed into result. - long idigit; // idigit is the iterate of digits in a. + int32_t idigit; // idigit is the iterate of digits in a. for ( idigit = 0; idigit < a->cdigit; idigit++ ) { mulnumx( &pnumret, num_radix); // WARNING: // This should just smack in each digit into a 'special' thisdigit. // and not do the overhead of recreating the number type each time. - thisdigit = longtonum( *ptrdigit--, BASEX ); + thisdigit = i32tonum( *ptrdigit--, BASEX ); addnum( &pnumret, thisdigit, BASEX ); destroynum( thisdigit ); } // Calculate the exponent of the external base for scaling. - numpowlongx( &num_radix, a->exp ); + numpowi32x( &num_radix, a->exp ); // ... and scale the result. mulnumx( &pnumret, num_radix); @@ -391,7 +469,7 @@ PRAT StringToRat(bool mantissaIsNegative, wstring_view mantissa, bool exponentIs } // Deal with exponent - long expt = 0; + int32_t expt = 0; if (!exponent.empty()) { // Exponent specified, convert to number form. @@ -404,18 +482,18 @@ PRAT StringToRat(bool mantissaIsNegative, wstring_view mantissa, bool exponentIs } // Convert exponent number form to native integral form, and cleanup. - expt = numtolong(numExp, radix); + expt = numtoi32(numExp, radix); destroynum(numExp); } // Convert native integral exponent form to rational multiplier form. - PNUMBER pnumexp = longtonum(radix, BASEX); - numpowlongx(&pnumexp, abs(expt)); + PNUMBER pnumexp = i32tonum(radix, BASEX); + numpowi32x(&pnumexp, abs(expt)); PRAT pratexp = nullptr; createrat(pratexp); DUPNUM(pratexp->pp, pnumexp); - pratexp->pq = longtonum(1, BASEX); + pratexp->pq = i32tonum(1, BASEX); destroynum(pnumexp); if (exponentIsNegative) @@ -574,11 +652,11 @@ wchar_t NormalizeCharDigit(wchar_t c, uint32_t radix) PNUMBER StringToNumber(wstring_view numberString, uint32_t radix, int32_t precision) { - long expSign = 1L; // expSign is exponent sign ( +/- 1 ) - long expValue = 0L; // expValue is exponent mantissa, should be unsigned + int32_t expSign = 1L; // expSign is exponent sign ( +/- 1 ) + int32_t expValue = 0L; // expValue is exponent mantissa, should be unsigned PNUMBER pnumret = nullptr; - createnum(pnumret, static_cast(numberString.length())); + createnum(pnumret, static_cast(numberString.length())); pnumret->sign = 1L; pnumret->cdigit = 0; pnumret->exp = 0; @@ -637,7 +715,7 @@ PNUMBER StringToNumber(wstring_view numberString, uint32_t radix, int32_t precis if (pos != wstring_view::npos) { expValue *= radix; - expValue += static_cast(pos); + expValue += static_cast(pos); } else { @@ -683,7 +761,7 @@ PNUMBER StringToNumber(wstring_view numberString, uint32_t radix, int32_t precis } else { - while (pnumret->cdigit < static_cast(numberString.length())) + while (pnumret->cdigit < static_cast(numberString.length())) { pnumret->cdigit++; pnumret->exp--; @@ -706,65 +784,65 @@ PNUMBER StringToNumber(wstring_view numberString, uint32_t radix, int32_t precis //----------------------------------------------------------------------------- // -// FUNCTION: longtorat +// FUNCTION: i32torat // -// ARGUMENTS: long +// ARGUMENTS: int32_t // -// RETURN: Rational representation of long input. +// RETURN: Rational representation of int32_t input. // -// DESCRIPTION: Converts long input to rational (p over q) -// form, where q is 1 and p is the long. +// DESCRIPTION: Converts int32_t input to rational (p over q) +// form, where q is 1 and p is the int32_t. // //----------------------------------------------------------------------------- -PRAT longtorat( _In_ long inlong ) +PRAT i32torat( _In_ int32_t ini32 ) { PRAT pratret= nullptr; createrat( pratret ); - pratret->pp = longtonum(inlong, BASEX ); - pratret->pq = longtonum(1L, BASEX ); + pratret->pp = i32tonum(ini32, BASEX ); + pratret->pq = i32tonum(1L, BASEX ); return( pratret ); } //----------------------------------------------------------------------------- // -// FUNCTION: Ulongtorat +// FUNCTION: Ui32torat // -// ARGUMENTS: ulong +// ARGUMENTS: ui32 // -// RETURN: Rational representation of unsigned long input. +// RETURN: Rational representation of uint32_t input. // -// DESCRIPTION: Converts unsigned long input to rational (p over q) -// form, where q is 1 and p is the unsigned long. Being unsigned cant take negative +// DESCRIPTION: Converts uint32_t input to rational (p over q) +// form, where q is 1 and p is the uint32_t. Being unsigned cant take negative // numbers, but the full range of unsigned numbers // //----------------------------------------------------------------------------- -PRAT Ulongtorat( _In_ unsigned long inulong ) +PRAT Ui32torat( _In_ uint32_t inui32 ) { PRAT pratret= nullptr; createrat( pratret ); - pratret->pp = Ulongtonum(inulong, BASEX ); - pratret->pq = longtonum(1L, BASEX ); + pratret->pp = Ui32tonum(inui32, BASEX ); + pratret->pq = i32tonum(1L, BASEX ); return( pratret ); } //----------------------------------------------------------------------------- // -// FUNCTION: longtonum +// FUNCTION: i32tonum // -// ARGUMENTS: long input and radix requested. +// ARGUMENTS: int32_t input and radix requested. // // RETURN: number // // DESCRIPTION: Returns a number representation in the -// base requested of the long value passed in. +// base requested of the int32_t value passed in. // //----------------------------------------------------------------------------- -PNUMBER longtonum( long inlong, uint32_t radix) +PNUMBER i32tonum( int32_t ini32, uint32_t radix) { MANTTYPE *pmant; @@ -774,10 +852,10 @@ PNUMBER longtonum( long inlong, uint32_t radix) pmant = pnumret->mant; pnumret->cdigit = 0; pnumret->exp = 0; - if ( inlong < 0 ) + if ( ini32 < 0 ) { pnumret->sign = -1; - inlong *= -1; + ini32 *= -1; } else { @@ -785,30 +863,30 @@ PNUMBER longtonum( long inlong, uint32_t radix) } do { - *pmant++ = (MANTTYPE)(inlong % radix); - inlong /= radix; + *pmant++ = (MANTTYPE)(ini32 % radix); + ini32 /= radix; pnumret->cdigit++; - } while ( inlong ); + } while ( ini32 ); return( pnumret ); } //----------------------------------------------------------------------------- // -// FUNCTION: Ulongtonum +// FUNCTION: Ui32tonum // -// ARGUMENTS: ULONG input and radix requested. +// ARGUMENTS: uint32_t input and radix requested. // // RETURN: number // // DESCRIPTION: Returns a number representation in the -// base requested of the unsigned long value passed in. Being unsigned number it has no +// base requested of the uint32_t value passed in. Being unsigned number it has no // negative number and takes the full range of unsigned number // //----------------------------------------------------------------------------- -PNUMBER Ulongtonum(unsigned long inlong, uint32_t radix) +PNUMBER Ui32tonum(uint32_t ini32, uint32_t radix) { MANTTYPE *pmant; PNUMBER pnumret= nullptr; @@ -820,10 +898,10 @@ PNUMBER Ulongtonum(unsigned long inlong, uint32_t radix) pnumret->sign = 1; do { - *pmant++ = (MANTTYPE)(inlong % radix); - inlong /= radix; + *pmant++ = (MANTTYPE)(ini32 % radix); + ini32 /= radix; pnumret->cdigit++; - } while ( inlong ); + } while ( ini32 ); return( pnumret ); } @@ -831,23 +909,23 @@ PNUMBER Ulongtonum(unsigned long inlong, uint32_t radix) //----------------------------------------------------------------------------- // -// FUNCTION: rattolong +// FUNCTION: rattoi32 // // ARGUMENTS: rational number in internal base, integer radix and int32_t precision. // -// RETURN: long +// RETURN: int32_t // -// DESCRIPTION: returns the long representation of the +// DESCRIPTION: returns the int32_t representation of the // number input. Assumes that the number is in the internal // base. // //----------------------------------------------------------------------------- -long rattolong( _In_ PRAT prat , uint32_t radix, int32_t precision) +int32_t rattoi32( _In_ PRAT prat , uint32_t radix, int32_t precision) { - if ( rat_gt( prat, rat_max_long, precision) || rat_lt( prat, rat_min_long, precision) ) + if ( rat_gt( prat, rat_max_i32, precision) || rat_lt( prat, rat_min_i32, precision) ) { - // Don't attempt rattolong of anything too big or small + // Don't attempt rattoi32 of anything too big or small throw( CALC_E_DOMAIN ); } @@ -858,7 +936,7 @@ long rattolong( _In_ PRAT prat , uint32_t radix, int32_t precision) divnumx( &(pint->pp), pint->pq, precision); DUPNUM( pint->pq, num_one ); - long lret = numtolong( pint->pp, BASEX ); + int32_t lret = numtoi32( pint->pp, BASEX ); destroyrat(pint); @@ -867,22 +945,22 @@ long rattolong( _In_ PRAT prat , uint32_t radix, int32_t precision) //----------------------------------------------------------------------------- // -// FUNCTION: rattoUlong +// FUNCTION: rattoUi32 // // ARGUMENTS: rational number in internal base, integer radix and int32_t precision. // -// RETURN: Ulong +// RETURN: Ui32 // -// DESCRIPTION: returns the Ulong representation of the +// DESCRIPTION: returns the Ui32 representation of the // number input. Assumes that the number is in the internal // base. // //----------------------------------------------------------------------------- -unsigned long rattoUlong( _In_ PRAT prat, uint32_t radix, int32_t precision) +uint32_t rattoUi32( _In_ PRAT prat, uint32_t radix, int32_t precision) { if ( rat_gt( prat, rat_dword, precision) || rat_lt( prat, rat_zero, precision) ) { - // Don't attempt rattoulong of anything too big or small + // Don't attempt rattoui32 of anything too big or small throw( CALC_E_DOMAIN ); } @@ -893,7 +971,7 @@ unsigned long rattoUlong( _In_ PRAT prat, uint32_t radix, int32_t precision) divnumx( &(pint->pp), pint->pq, precision); DUPNUM( pint->pq, num_one ); - unsigned long lret = numtolong( pint->pp, BASEX ); // This happens to work even if it is only signed + uint32_t lret = numtoi32( pint->pp, BASEX ); // This happens to work even if it is only signed destroyrat(pint); @@ -903,11 +981,11 @@ unsigned long rattoUlong( _In_ PRAT prat, uint32_t radix, int32_t precision) //----------------------------------------------------------------------------- // -// FUNCTION: rattoUlonglong +// FUNCTION: rattoUi64 // // ARGUMENTS: rational number in internal base, integer radix and int32_t precision // -// RETURN: Ulonglong +// RETURN: Ui64 // // DESCRIPTION: returns the 64 bit (irrespective of which processor this is running in) representation of the // number input. Assumes that the number is in the internal @@ -916,50 +994,50 @@ unsigned long rattoUlong( _In_ PRAT prat, uint32_t radix, int32_t precision) // internal base chosen happens to be 2^32, this is easier. //----------------------------------------------------------------------------- -ULONGLONG rattoUlonglong( _In_ PRAT prat, uint32_t radix, int32_t precision) +uint64_t rattoUi64( _In_ PRAT prat, uint32_t radix, int32_t precision) { PRAT pint = nullptr; // first get the LO 32 bit word DUPRAT(pint, prat); andrat(&pint, rat_dword, radix, precision); // & 0xFFFFFFFF (2 ^ 32 -1) - unsigned long lo = rattoUlong(pint, radix, precision); // wont throw exception because already hi-dword chopped off + uint32_t lo = rattoUi32(pint, radix, precision); // wont throw exception because already hi-dword chopped off DUPRAT(pint, prat); // previous pint will get freed by this as well - PRAT prat32 = longtorat(32); + PRAT prat32 = i32torat(32); rshrat(&pint, prat32, radix, precision); intrat( &pint, radix, precision); andrat(&pint, rat_dword, radix, precision); // & 0xFFFFFFFF (2 ^ 32 -1) - unsigned long hi = rattoUlong(pint, radix, precision); + uint32_t hi = rattoUi32(pint, radix, precision); destroyrat(prat32); destroyrat(pint); - return (((ULONGLONG)hi << 32) | lo); + return (((uint64_t)hi << 32) | lo); } //----------------------------------------------------------------------------- // -// FUNCTION: numtolong +// FUNCTION: numtoi32 // // ARGUMENTS: number input and base of that number. // -// RETURN: long +// RETURN: int32_t // -// DESCRIPTION: returns the long representation of the +// DESCRIPTION: returns the int32_t representation of the // number input. Assumes that the number is really in the // base claimed. // //----------------------------------------------------------------------------- -long numtolong( _In_ PNUMBER pnum, uint32_t radix ) +int32_t numtoi32( _In_ PNUMBER pnum, uint32_t radix ) { - long lret = 0; + int32_t lret = 0; MANTTYPE *pmant = pnum->mant; pmant += pnum->cdigit - 1; - long expt = pnum->exp; - for (long length = pnum->cdigit; length > 0 && length + expt > 0; length--) + int32_t expt = pnum->exp; + for (int32_t length = pnum->cdigit; length > 0 && length + expt > 0; length--) { lret *= radix; lret += *(pmant--); @@ -986,10 +1064,10 @@ long numtolong( _In_ PNUMBER pnum, uint32_t radix ) // //----------------------------------------------------------------------------- -bool stripzeroesnum(_Inout_ PNUMBER pnum, long starting) +bool stripzeroesnum(_Inout_ PNUMBER pnum, int32_t starting) { MANTTYPE *pmant; - long cdigits; + int32_t cdigits; bool fstrip = false; // point pmant to the LeastCalculatedDigit @@ -1042,10 +1120,10 @@ bool stripzeroesnum(_Inout_ PNUMBER pnum, long starting) wstring NumberToString(_Inout_ PNUMBER& pnum, int format, uint32_t radix, int32_t precision) { stripzeroesnum(pnum, precision + 2); - long length = pnum->cdigit; - long exponent = pnum->exp + length; // Actual number of digits to the left of decimal + int32_t length = pnum->cdigit; + int32_t exponent = pnum->exp + length; // Actual number of digits to the left of decimal - long oldFormat = format; + int32_t oldFormat = format; if (exponent > precision && format == FMT_FLOAT) { // Force scientific mode to prevent user from assuming 33rd digit is exact. @@ -1065,7 +1143,7 @@ wstring NumberToString(_Inout_ PNUMBER& pnum, int format, uint32_t radix, int32_ if (!zernum(pnum) && (pnum->cdigit >= precision || (length - exponent > precision && exponent >= -MAX_ZEROS_AFTER_DECIMAL))) { // Otherwise round. - round = longtonum(radix, radix); + round = i32tonum(radix, radix); divnum(&round, num_two, radix, precision); // Make round number exponent one below the LSD for the number. @@ -1110,7 +1188,7 @@ wstring NumberToString(_Inout_ PNUMBER& pnum, int format, uint32_t radix, int32_ if (round != nullptr) { addnum(&pnum, round, radix); - long offset = (pnum->cdigit + pnum->exp) - (round->cdigit + round->exp); + int32_t offset = (pnum->cdigit + pnum->exp) - (round->cdigit + round->exp); destroynum(round); if (stripzeroesnum(pnum, offset)) { @@ -1126,7 +1204,7 @@ wstring NumberToString(_Inout_ PNUMBER& pnum, int format, uint32_t radix, int32_ // Set up all the post rounding stuff. bool useSciForm = false; - long eout = exponent - 1; // Displayed exponent. + int32_t eout = exponent - 1; // Displayed exponent. MANTTYPE *pmant = pnum->mant + pnum->cdigit - 1; // Case where too many digits are to the left of the decimal or // FMT_SCIENTIFIC or FMT_ENGINEERING was specified. @@ -1240,7 +1318,7 @@ wstring NumberToString(_Inout_ PNUMBER& pnum, int format, uint32_t radix, int32_ // // ARGUMENTS: // PRAT *representation of a number. -// long representation of base to dump to screen. +// i32 representation of base to dump to screen. // fmt, one of FMT_FLOAT FMT_SCIENTIFIC or FMT_ENGINEERING // precision uint32_t // @@ -1270,8 +1348,8 @@ PNUMBER RatToNumber(_In_ PRAT prat, uint32_t radix, int32_t precision) DUPRAT(temprat, prat); // Convert p and q of rational form from internal base to requested base. // Scale by largest power of BASEX possible. - long scaleby = min(temprat->pp->exp, temprat->pq->exp); - scaleby = max(scaleby, 0); + int32_t scaleby = min(temprat->pp->exp, temprat->pq->exp); + scaleby = max(scaleby, 0); temprat->pp->exp -= scaleby; temprat->pq->exp -= scaleby; @@ -1359,12 +1437,12 @@ PNUMBER gcd( _In_ PNUMBER a, _In_ PNUMBER b) //----------------------------------------------------------------------------- // -// FUNCTION: longfactnum +// FUNCTION: i32factnum // // ARGUMENTS: -// long integer to factorialize. -// long integer representing base of answer. -// unsigned long integer for radix +// int32_t integer to factorialize. +// int32_t integer representing base of answer. +// uint32_t integer for radix // // RETURN: Factorial of input in radix PNUMBER form. // @@ -1372,17 +1450,17 @@ PNUMBER gcd( _In_ PNUMBER a, _In_ PNUMBER b) // //----------------------------------------------------------------------------- -PNUMBER longfactnum(long inlong, uint32_t radix) +PNUMBER i32factnum(int32_t ini32, uint32_t radix) { PNUMBER lret= nullptr; PNUMBER tmp= nullptr; - lret = longtonum( 1, radix); + lret = i32tonum( 1, radix); - while ( inlong > 0 ) + while ( ini32 > 0 ) { - tmp = longtonum( inlong--, radix); + tmp = i32tonum( ini32--, radix); mulnum( &lret, tmp, radix); destroynum( tmp ); } @@ -1391,30 +1469,30 @@ PNUMBER longfactnum(long inlong, uint32_t radix) //----------------------------------------------------------------------------- // -// FUNCTION: longprodnum +// FUNCTION: i32prodnum // // ARGUMENTS: -// long integer to factorialize. -// long integer representing base of answer. -// unsigned long integer for radix +// int32_t integer to factorialize. +// int32_t integer representing base of answer. +// uint32_t integer for radix // // RETURN: Factorial of input in base PNUMBER form. // //----------------------------------------------------------------------------- -PNUMBER longprodnum(long start, long stop, uint32_t radix) +PNUMBER i32prodnum(int32_t start, int32_t stop, uint32_t radix) { PNUMBER lret= nullptr; PNUMBER tmp= nullptr; - lret = longtonum( 1, radix); + lret = i32tonum( 1, radix); while ( start <= stop ) { if ( start ) { - tmp = longtonum( start, radix); + tmp = i32tonum( start, radix); mulnum( &lret, tmp, radix); destroynum( tmp ); } @@ -1425,10 +1503,10 @@ PNUMBER longprodnum(long start, long stop, uint32_t radix) //----------------------------------------------------------------------------- // -// FUNCTION: numpowlong +// FUNCTION: numpowi32 // -// ARGUMENTS: root as number power as long and radix of -// number along with the precision value in long. +// ARGUMENTS: root as number power as int32_t and radix of +// number along with the precision value in int32_t. // // RETURN: None root is changed. // @@ -1437,9 +1515,9 @@ PNUMBER longprodnum(long start, long stop, uint32_t radix) // //----------------------------------------------------------------------------- -void numpowlong( _Inout_ PNUMBER *proot, long power, uint32_t radix, int32_t precision) +void numpowi32( _Inout_ PNUMBER *proot, int32_t power, uint32_t radix, int32_t precision) { - PNUMBER lret = longtonum( 1, radix ); + PNUMBER lret = i32tonum( 1, radix ); while ( power > 0 ) { @@ -1458,9 +1536,9 @@ void numpowlong( _Inout_ PNUMBER *proot, long power, uint32_t radix, int32_t pre //----------------------------------------------------------------------------- // -// FUNCTION: ratpowlong +// FUNCTION: ratpowi32 // -// ARGUMENTS: root as rational, power as long and precision as uint32_t. +// ARGUMENTS: root as rational, power as int32_t and precision as int32_t. // // RETURN: None root is changed. // @@ -1469,14 +1547,14 @@ void numpowlong( _Inout_ PNUMBER *proot, long power, uint32_t radix, int32_t pre // //----------------------------------------------------------------------------- -void ratpowlong( _Inout_ PRAT *proot, long power, int32_t precision) +void ratpowi32( _Inout_ PRAT *proot, int32_t power, int32_t precision) { if ( power < 0 ) { // Take the positive power and invert answer. PNUMBER pnumtemp = nullptr; - ratpowlong( proot, -power, precision); + ratpowi32( proot, -power, precision); pnumtemp = (*proot)->pp; (*proot)->pp = (*proot)->pq; (*proot)->pq = pnumtemp; @@ -1485,7 +1563,7 @@ void ratpowlong( _Inout_ PRAT *proot, long power, int32_t precision) { PRAT lret= nullptr; - lret = longtorat( 1 ); + lret = i32torat( 1 ); while ( power > 0 ) { diff --git a/src/CalcManager/Ratpack/exp.cpp b/src/CalcManager/Ratpack/exp.cpp index 8e0e58af..e4939db4 100644 --- a/src/CalcManager/Ratpack/exp.cpp +++ b/src/CalcManager/Ratpack/exp.cpp @@ -14,7 +14,6 @@ // // //----------------------------------------------------------------------------- -#include "pch.h" #include "ratpak.h" @@ -50,7 +49,7 @@ void _exprat( PRAT *px, int32_t precision) addnum(&(pret->pq),num_one, BASEX); DUPRAT(thisterm,pret); - n2=longtonum(0L, BASEX); + n2=i32tonum(0L, BASEX); do { NEXTTERM(*px, INC(n2) DIVNUM(n2), precision); @@ -64,7 +63,7 @@ void exprat( PRAT *px, uint32_t radix, int32_t precision) { PRAT pwr= nullptr; PRAT pint= nullptr; - long intpwr; + int32_t intpwr; if ( rat_gt( *px, rat_max_exp, precision) || rat_lt( *px, rat_min_exp, precision) ) { @@ -77,8 +76,8 @@ void exprat( PRAT *px, uint32_t radix, int32_t precision) intrat(&pint, radix, precision); - intpwr = rattolong(pint, radix, precision); - ratpowlong( &pwr, intpwr, precision); + intpwr = rattoi32(pint, radix, precision); + ratpowi32( &pwr, intpwr, precision); subrat(px, pint, precision); @@ -140,7 +139,7 @@ void _lograt( PRAT *px, int32_t precision) DUPRAT(pret,*px); DUPRAT(thisterm,*px); - n2=longtonum(1L, BASEX); + n2=i32tonum(1L, BASEX); (*px)->pp->sign *= -1; do { @@ -183,10 +182,10 @@ void lograt( PRAT *px, int32_t precision) { // Take advantage of px's base BASEX to scale quickly down to // a reasonable range. - long intpwr; + int32_t intpwr; intpwr=LOGRAT2(*px)-1; (*px)->pq->exp += intpwr; - pwr=longtorat(intpwr*BASEXPWR); + pwr=i32torat(intpwr*BASEXPWR); mulrat(&pwr, ln_two, precision); // ln(x+e)-ln(x) looks close to e when x is close to one using some // expansions. This means we can trim past precision digits+1. @@ -309,7 +308,7 @@ void powratNumeratorDenominator(PRAT *px, PRAT y, uint32_t radix, int32_t precis // Calculate the following use the Powers of Powers rule: // px ^ (yNum/yDenom) == px ^ yNum ^ (1/yDenom) - // 1. For px ^ yNum, we call powratcomp directly which will call ratpowlong + // 1. For px ^ yNum, we call powratcomp directly which will call ratpowi32 // and store the result in pxPowNum // 2. For pxPowNum ^ (1/yDenom), we call powratcomp // 3. Validate the result of 2 by adding/subtracting 0.5, flooring and call powratcomp with yDenom @@ -408,7 +407,7 @@ void powratNumeratorDenominator(PRAT *px, PRAT y, uint32_t radix, int32_t precis //--------------------------------------------------------------------------- void powratcomp(PRAT *px, PRAT y, uint32_t radix, int32_t precision) { - long sign = ((*px)->pp->sign * (*px)->pq->sign); + int32_t sign = SIGN(*px); // Take the absolute value (*px)->pp->sign = 1; @@ -451,12 +450,12 @@ void powratcomp(PRAT *px, PRAT y, uint32_t radix, int32_t precision) fracrat(&podd, radix, precision); if ( rat_gt( podd, rat_negsmallest, precision) && rat_lt( podd, rat_smallest, precision) ) { - // If power is an integer let ratpowlong deal with it. + // If power is an integer let ratpowi32 deal with it. PRAT iy = nullptr; - long inty; + int32_t inty; DUPRAT(iy,y); subrat(&iy, podd, precision); - inty = rattolong(iy, radix, precision); + inty = rattoi32(iy, radix, precision); PRAT plnx = nullptr; DUPRAT(plnx,*px); @@ -472,7 +471,7 @@ void powratcomp(PRAT *px, PRAT y, uint32_t radix, int32_t precision) throw( CALC_E_DOMAIN ); } destroyrat(plnx); - ratpowlong(px, inty, precision); + ratpowi32(px, inty, precision); if ( ( inty & 1 ) == 0 ) { sign=1; diff --git a/src/CalcManager/Ratpack/fact.cpp b/src/CalcManager/Ratpack/fact.cpp index 1a992bc0..bdcbccb0 100644 --- a/src/CalcManager/Ratpack/fact.cpp +++ b/src/CalcManager/Ratpack/fact.cpp @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. //----------------------------------------------------------------------------- @@ -13,7 +13,6 @@ // Contains fact(orial) and supporting _gamma functions. // //----------------------------------------------------------------------------- -#include "pch.h" #include "ratpak.h" @@ -72,14 +71,14 @@ void _gamma( PRAT *pn, uint32_t radix, int32_t precision) PRAT mpy= nullptr; PRAT ratprec = nullptr; PRAT ratRadix = nullptr; - long oldprec; + int32_t oldprec; // Set up constants and initial conditions oldprec = precision; - ratprec = longtorat( oldprec ); + ratprec = i32torat( oldprec ); // Find the best 'A' for convergence to the required precision. - a=longtorat( radix ); + a=i32torat( radix ); lograt(&a, precision); mulrat(&a, ratprec, precision); @@ -96,7 +95,7 @@ void _gamma( PRAT *pn, uint32_t radix, int32_t precision) // The following code is equivalent to // precision += ln(exp(a)*pow(a,n+1.5))-ln(radix)); DUPRAT(tmp,*pn); - one_pt_five=longtorat( 3L ); + one_pt_five=i32torat( 3L ); divrat( &one_pt_five, rat_two, precision); addrat( &tmp, one_pt_five, precision); DUPRAT(term,a); @@ -105,15 +104,15 @@ void _gamma( PRAT *pn, uint32_t radix, int32_t precision) exprat( &tmp, radix, precision); mulrat( &term, tmp, precision); lograt( &term, precision); - ratRadix = longtorat(radix); + ratRadix = i32torat(radix); DUPRAT(tmp,ratRadix); lograt( &tmp, precision); subrat( &term, tmp, precision); - precision += rattolong( term, radix, precision); + precision += rattoi32( term, radix, precision); // Set up initial terms for series, refer to series in above comment block. DUPRAT(factorial,rat_one); // Start factorial out with one - count = longtonum( 0L, BASEX ); + count = i32tonum( 0L, BASEX ); DUPRAT(mpy,a); powratcomp(&mpy,*pn, radix, precision); @@ -216,7 +215,7 @@ void factrat( PRAT *px, uint32_t radix, int32_t precision) // Check for negative integers and throw an error. if ( ( zerrat(frac) || ( LOGRATRADIX(frac) <= -precision) ) && - ( (*px)->pp->sign * (*px)->pq->sign == -1 ) ) + ( SIGN(*px) == -1 ) ) { throw CALC_E_DOMAIN; } diff --git a/src/CalcManager/Ratpack/itrans.cpp b/src/CalcManager/Ratpack/itrans.cpp index ef687b93..1521308d 100644 --- a/src/CalcManager/Ratpack/itrans.cpp +++ b/src/CalcManager/Ratpack/itrans.cpp @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. //----------------------------------------------------------------------------- @@ -15,7 +15,6 @@ // Special Information // //----------------------------------------------------------------------------- -#include "pch.h" #include "ratpak.h" @@ -92,11 +91,9 @@ void asinanglerat( _Inout_ PRAT *pa, ANGLE_TYPE angletype, uint32_t radix, int32 void asinrat( PRAT *px, uint32_t radix, int32_t precision) { - long sgn; PRAT pret= nullptr; PRAT phack= nullptr; - - sgn = (*px)->pp->sign* (*px)->pq->sign; + int32_t sgn = SIGN(*px); (*px)->pp->sign = 1; (*px)->pq->sign = 1; @@ -186,8 +183,8 @@ void _acosrat( PRAT *px, int32_t precision) CREATETAYLOR(); createrat(thisterm); - thisterm->pp=longtonum( 1L, BASEX ); - thisterm->pq=longtonum( 1L, BASEX ); + thisterm->pp=i32tonum( 1L, BASEX ); + thisterm->pq=i32tonum( 1L, BASEX ); DUPNUM(n2,num_one); @@ -204,9 +201,7 @@ void _acosrat( PRAT *px, int32_t precision) void acosrat( PRAT *px, uint32_t radix, int32_t precision) { - long sgn; - - sgn = (*px)->pp->sign*(*px)->pq->sign; + int32_t sgn = SIGN(*px); (*px)->pp->sign = 1; (*px)->pq->sign = 1; @@ -291,10 +286,8 @@ void _atanrat( PRAT *px, int32_t precision) void atanrat( PRAT *px, uint32_t radix, int32_t precision) { - long sgn; PRAT tmpx= nullptr; - - sgn = (*px)->pp->sign * (*px)->pq->sign; + int32_t sgn = SIGN(*px); (*px)->pp->sign = 1; (*px)->pq->sign = 1; diff --git a/src/CalcManager/Ratpack/itransh.cpp b/src/CalcManager/Ratpack/itransh.cpp index d6734a1f..50941287 100644 --- a/src/CalcManager/Ratpack/itransh.cpp +++ b/src/CalcManager/Ratpack/itransh.cpp @@ -16,7 +16,6 @@ // // //----------------------------------------------------------------------------- -#include "pch.h" #include "ratpak.h" diff --git a/src/CalcManager/Ratpack/logic.cpp b/src/CalcManager/Ratpack/logic.cpp index ab5a63ed..7939ce26 100644 --- a/src/CalcManager/Ratpack/logic.cpp +++ b/src/CalcManager/Ratpack/logic.cpp @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. //--------------------------------------------------------------------------- @@ -13,59 +13,58 @@ // Contains routines for and, or, xor, not and other support // //--------------------------------------------------------------------------- -#include "pch.h" #include "ratpak.h" +using namespace std; - -void lshrat( PRAT *pa, PRAT b, uint32_t radix, int32_t precision) +void lshrat(PRAT *pa, PRAT b, uint32_t radix, int32_t precision) { - PRAT pwr= nullptr; - long intb; + PRAT pwr = nullptr; + int32_t intb; intrat(pa, radix, precision); - if ( !zernum( (*pa)->pp ) ) - { + if (!zernum((*pa)->pp)) + { // If input is zero we're done. - if ( rat_gt( b, rat_max_exp, precision) ) - { + if (rat_gt(b, rat_max_exp, precision)) + { // Don't attempt lsh of anything big - throw( CALC_E_DOMAIN ); - } - intb = rattolong(b, radix, precision); - DUPRAT(pwr,rat_two); - ratpowlong(&pwr, intb, precision); + throw(CALC_E_DOMAIN); + } + intb = rattoi32(b, radix, precision); + DUPRAT(pwr, rat_two); + ratpowi32(&pwr, intb, precision); mulrat(pa, pwr, precision); destroyrat(pwr); - } + } } -void rshrat( PRAT *pa, PRAT b, uint32_t radix, int32_t precision) +void rshrat(PRAT *pa, PRAT b, uint32_t radix, int32_t precision) { - PRAT pwr= nullptr; - long intb; + PRAT pwr = nullptr; + int32_t intb; intrat(pa, radix, precision); - if ( !zernum( (*pa)->pp ) ) - { + if (!zernum((*pa)->pp)) + { // If input is zero we're done. - if ( rat_lt( b, rat_min_exp, precision) ) - { + if (rat_lt(b, rat_min_exp, precision)) + { // Don't attempt rsh of anything big and negative. - throw( CALC_E_DOMAIN ); - } - intb = rattolong(b, radix, precision); - DUPRAT(pwr,rat_two); - ratpowlong(&pwr, intb, precision); + throw(CALC_E_DOMAIN); + } + intb = rattoi32(b, radix, precision); + DUPRAT(pwr, rat_two); + ratpowi32(&pwr, intb, precision); divrat(pa, pwr, precision); destroyrat(pwr); - } + } } -void boolrat( PRAT *pa, PRAT b, int func, uint32_t radix, int32_t precision); -void boolnum( PNUMBER *pa, PNUMBER b, int func ); +void boolrat(PRAT *pa, PRAT b, int func, uint32_t radix, int32_t precision); +void boolnum(PNUMBER *pa, PNUMBER b, int func); enum { @@ -74,22 +73,22 @@ enum { FUNC_XOR } BOOL_FUNCS; -void andrat( PRAT *pa, PRAT b, uint32_t radix, int32_t precision) +void andrat(PRAT *pa, PRAT b, uint32_t radix, int32_t precision) { - boolrat( pa, b, FUNC_AND, radix, precision); + boolrat(pa, b, FUNC_AND, radix, precision); } -void orrat( PRAT *pa, PRAT b, uint32_t radix, int32_t precision) +void orrat(PRAT *pa, PRAT b, uint32_t radix, int32_t precision) { - boolrat( pa, b, FUNC_OR, radix, precision); + boolrat(pa, b, FUNC_OR, radix, precision); } -void xorrat( PRAT *pa, PRAT b, uint32_t radix, int32_t precision) +void xorrat(PRAT *pa, PRAT b, uint32_t radix, int32_t precision) { - boolrat( pa, b, FUNC_XOR, radix, precision); + boolrat(pa, b, FUNC_XOR, radix, precision); } //--------------------------------------------------------------------------- @@ -104,15 +103,15 @@ void xorrat( PRAT *pa, PRAT b, uint32_t radix, int32_t precision) // //--------------------------------------------------------------------------- -void boolrat( PRAT *pa, PRAT b, int func, uint32_t radix, int32_t precision) +void boolrat(PRAT *pa, PRAT b, int func, uint32_t radix, int32_t precision) { - PRAT tmp= nullptr; - intrat( pa, radix, precision); - DUPRAT(tmp,b); - intrat( &tmp, radix, precision); + PRAT tmp = nullptr; + intrat(pa, radix, precision); + DUPRAT(tmp, b); + intrat(&tmp, radix, precision); - boolnum( &((*pa)->pp), tmp->pp, func ); + boolnum(&((*pa)->pp), tmp->pp, func); destroyrat(tmp); } @@ -130,39 +129,39 @@ void boolrat( PRAT *pa, PRAT b, int func, uint32_t radix, int32_t precision) // //--------------------------------------------------------------------------- -void boolnum( PNUMBER *pa, PNUMBER b, int func ) +void boolnum(PNUMBER *pa, PNUMBER b, int func) { - PNUMBER c= nullptr; - PNUMBER a= nullptr; + PNUMBER c = nullptr; + PNUMBER a = nullptr; MANTTYPE *pcha; MANTTYPE *pchb; MANTTYPE *pchc; - long cdigits; - long mexp; + int32_t cdigits; + int32_t mexp; MANTTYPE da; MANTTYPE db; - a=*pa; - cdigits = max( a->cdigit+a->exp, b->cdigit+b->exp ) - - min( a->exp, b->exp ); - createnum( c, cdigits ); - c->exp = min( a->exp, b->exp ); + a = *pa; + cdigits = max(a->cdigit + a->exp, b->cdigit + b->exp) - + min(a->exp, b->exp); + createnum(c, cdigits); + c->exp = min(a->exp, b->exp); mexp = c->exp; c->cdigit = cdigits; pcha = a->mant; pchb = b->mant; pchc = c->mant; - for ( ;cdigits > 0; cdigits--, mexp++ ) + for (; cdigits > 0; cdigits--, mexp++) + { + da = (((mexp >= a->exp) && (cdigits + a->exp - c->exp > + (c->cdigit - a->cdigit))) ? + *pcha++ : 0); + db = (((mexp >= b->exp) && (cdigits + b->exp - c->exp > + (c->cdigit - b->cdigit))) ? + *pchb++ : 0); + switch (func) { - da = ( ( ( mexp >= a->exp ) && ( cdigits + a->exp - c->exp > - (c->cdigit - a->cdigit) ) ) ? - *pcha++ : 0 ); - db = ( ( ( mexp >= b->exp ) && ( cdigits + b->exp - c->exp > - (c->cdigit - b->cdigit) ) ) ? - *pchb++ : 0 ); - switch ( func ) - { case FUNC_AND: *pchc++ = da & db; break; @@ -172,15 +171,51 @@ void boolnum( PNUMBER *pa, PNUMBER b, int func ) case FUNC_XOR: *pchc++ = da ^ db; break; - } } + } c->sign = a->sign; - while ( c->cdigit > 1 && *(--pchc) == 0 ) - { + while (c->cdigit > 1 && *(--pchc) == 0) + { c->cdigit--; - } - destroynum( *pa ); - *pa=c; + } + destroynum(*pa); + *pa = c; +} + +//----------------------------------------------------------------------------- +// +// FUNCTION: remrat +// +// ARGUMENTS: pointer to a rational a second rational. +// +// RETURN: None, changes pointer. +// +// DESCRIPTION: Calculate the remainder of *pa / b, +// equivalent of 'pa % b' in C/C++ and produces a result +// that is either zero or has the same sign as the dividend. +// +//----------------------------------------------------------------------------- + +void remrat(PRAT *pa, PRAT b) + +{ + if (zerrat(b)) + { + throw CALC_E_INDEFINITE; + } + + PRAT tmp = nullptr; + DUPRAT(tmp, b); + + mulnumx(&((*pa)->pp), tmp->pq); + mulnumx(&(tmp->pp), (*pa)->pq); + remnum(&((*pa)->pp), tmp->pp, BASEX); + mulnumx(&((*pa)->pq), tmp->pq); + + // Get *pa back in the integer over integer form. + RENORMALIZE(*pa); + + destroyrat(tmp); } //----------------------------------------------------------------------------- @@ -191,28 +226,38 @@ void boolnum( PNUMBER *pa, PNUMBER b, int func ) // // RETURN: None, changes pointer. // -// DESCRIPTION: Does the rational equivalent of frac(*pa); +// DESCRIPTION: Calculate the remainder of *pa / b, with the sign of the result +// either zero or has the same sign as the divisor. +// NOTE: When *pa or b are negative, the result won't be the same as +// the C/C++ operator %, use remrat if it's the behavior you expect. // //----------------------------------------------------------------------------- -void modrat( PRAT *pa, PRAT b ) - +void modrat(PRAT *pa, PRAT b) { + //contrary to remrat(X, 0) returning 0, modrat(X, 0) must return X + if (zerrat(b)) + { + return; + } + PRAT tmp = nullptr; + DUPRAT(tmp, b); - if ( zerrat( b ) ) - { - throw CALC_E_INDEFINITE; - } - DUPRAT(tmp,b); + auto needAdjust = (SIGN(*pa) == -1 ? (SIGN(b) == 1) : (SIGN(b) == -1)); - mulnumx( &((*pa)->pp), tmp->pq ); - mulnumx( &(tmp->pp), (*pa)->pq ); - remnum( &((*pa)->pp), tmp->pp, BASEX ); - mulnumx( &((*pa)->pq), tmp->pq ); + mulnumx(&((*pa)->pp), tmp->pq); + mulnumx(&(tmp->pp), (*pa)->pq); + remnum(&((*pa)->pp), tmp->pp, BASEX); + mulnumx(&((*pa)->pq), tmp->pq); + + if (needAdjust && !zerrat(*pa)) + { + addrat(pa, b, BASEX); + } // Get *pa back in the integer over integer form. RENORMALIZE(*pa); - destroyrat( tmp ); + destroyrat(tmp); } diff --git a/src/CalcManager/Ratpack/num.cpp b/src/CalcManager/Ratpack/num.cpp index 817fe02c..7b45fea0 100644 --- a/src/CalcManager/Ratpack/num.cpp +++ b/src/CalcManager/Ratpack/num.cpp @@ -17,7 +17,8 @@ // // //----------------------------------------------------------------------------- -#include "pch.h" +#include +#include // for memmove #include "ratpak.h" using namespace std; @@ -66,14 +67,14 @@ void _addnum( PNUMBER *pa, PNUMBER b, uint32_t radix) MANTTYPE *pcha; // pcha is a pointer to the mantissa of a. MANTTYPE *pchb; // pchb is a pointer to the mantissa of b. MANTTYPE *pchc; // pchc is a pointer to the mantissa of c. - long cdigits; // cdigits is the max count of the digits results + int32_t cdigits; // cdigits is the max count of the digits results // used as a counter. - long mexp; // mexp is the exponent of the result. + int32_t mexp; // mexp is the exponent of the result. MANTTYPE da; // da is a single 'digit' after possible padding. MANTTYPE db; // db is a single 'digit' after possible padding. MANTTYPE cy=0; // cy is the value of a carry after adding two 'digits' - long fcompla = 0; // fcompla is a flag to signal a is negative. - long fcomplb = 0; // fcomplb is a flag to signal b is negative. + int32_t fcompla = 0; // fcompla is a flag to signal a is negative. + int32_t fcomplb = 0; // fcomplb is a flag to signal b is negative. a=*pa; @@ -205,7 +206,7 @@ void __inline mulnum( PNUMBER *pa, PNUMBER b, uint32_t radix) } else { // if pa is one and b isn't just copy b, and adjust the sign. - long sign = (*pa)->sign; + int32_t sign = (*pa)->sign; DUPNUM(*pa,b); (*pa)->sign *= sign; } @@ -226,14 +227,14 @@ void _mulnum( PNUMBER *pa, PNUMBER b, uint32_t radix) MANTTYPE *pchc; // pchc is a pointer to the mantissa of c. MANTTYPE *pchcoffset; // pchcoffset, is the anchor location of the next // single digit multiply partial result. - long iadigit = 0; // Index of digit being used in the first number. - long ibdigit = 0; // Index of digit being used in the second number. + int32_t iadigit = 0; // Index of digit being used in the first number. + int32_t ibdigit = 0; // Index of digit being used in the second number. MANTTYPE da = 0; // da is the digit from the fist number. TWO_MANTTYPE cy = 0; // cy is the carry resulting from the addition of // a multiplied row into the result. TWO_MANTTYPE mcy = 0; // mcy is the resultant from a single // multiply, AND the carry of that multiply. - long icdigit = 0; // Index of digit being calculated in final result. + int32_t icdigit = 0; // Index of digit being calculated in final result. a=*pa; ibdigit = a->cdigit + b->cdigit - 1; @@ -334,7 +335,7 @@ void remnum( PNUMBER *pa, PNUMBER b, uint32_t radix) } destroynum( lasttmp ); - lasttmp=longtonum( 0, radix); + lasttmp=i32tonum( 0, radix); while ( lessnum( tmp, *pa ) ) { @@ -394,7 +395,7 @@ void __inline divnum( PNUMBER *pa, PNUMBER b, uint32_t radix, int32_t precision) void _divnum( PNUMBER *pa, PNUMBER b, uint32_t radix, int32_t precision) { PNUMBER a = *pa; - long thismax = precision + 2; + int32_t thismax = precision + 2; if (thismax < a->cdigit) { thismax = a->cdigit; @@ -420,8 +421,8 @@ void _divnum( PNUMBER *pa, PNUMBER b, uint32_t radix, int32_t precision) // Build a table of multiplications of the divisor, this is quicker for // more than radix 'digits' - list numberList{ longtonum(0L, radix) }; - for (unsigned long i = 1; i < radix; i++) + list numberList{ i32tonum(0L, radix) }; + for (uint32_t i = 1; i < radix; i++) { PNUMBER newValue = nullptr; DUPNUM(newValue, numberList.front()); @@ -431,8 +432,8 @@ void _divnum( PNUMBER *pa, PNUMBER b, uint32_t radix, int32_t precision) } destroynum(tmp); - long digit; - long cdigits = 0; + int32_t digit; + int32_t cdigits = 0; while (cdigits++ < thismax && !zernum(rem)) { digit = radix - 1; @@ -505,11 +506,11 @@ void _divnum( PNUMBER *pa, PNUMBER b, uint32_t radix, int32_t precision) bool equnum( PNUMBER a, PNUMBER b ) { - long diff; + int32_t diff; MANTTYPE *pa; MANTTYPE *pb; - long cdigits; - long ccdigits; + int32_t cdigits; + int32_t ccdigits; MANTTYPE da; MANTTYPE db; @@ -573,11 +574,11 @@ bool equnum( PNUMBER a, PNUMBER b ) bool lessnum( PNUMBER a, PNUMBER b ) { - long diff; + int32_t diff; MANTTYPE *pa; MANTTYPE *pb; - long cdigits; - long ccdigits; + int32_t cdigits; + int32_t ccdigits; MANTTYPE da; MANTTYPE db; @@ -635,7 +636,7 @@ bool lessnum( PNUMBER a, PNUMBER b ) bool zernum( PNUMBER a ) { - long length; + int32_t length; MANTTYPE *pcha; length = a->cdigit; pcha = a->mant; diff --git a/src/CalcManager/Ratpack/rat.cpp b/src/CalcManager/Ratpack/rat.cpp index e101458a..e5a6d254 100644 --- a/src/CalcManager/Ratpack/rat.cpp +++ b/src/CalcManager/Ratpack/rat.cpp @@ -16,7 +16,6 @@ // //----------------------------------------------------------------------------- -#include "pch.h" #include "ratpak.h" using namespace std; diff --git a/src/CalcManager/Ratpack/ratconst.h b/src/CalcManager/Ratpack/ratconst.h index be24b002..7367cd36 100644 --- a/src/CalcManager/Ratpack/ratconst.h +++ b/src/CalcManager/Ratpack/ratconst.h @@ -325,26 +325,26 @@ inline const NUMBER init_q_rat_dword = { { 1,} }; // Autogenerated by _dumprawrat in support.cpp -inline const NUMBER init_p_rat_max_long = { +inline const NUMBER init_p_rat_max_i32 = { 1, 1, 0, { 2147483647,} }; -inline const NUMBER init_q_rat_max_long = { +inline const NUMBER init_q_rat_max_i32 = { 1, 1, 0, { 1,} }; // Autogenerated by _dumprawrat in support.cpp -inline const NUMBER init_p_rat_min_long = { +inline const NUMBER init_p_rat_min_i32 = { -1, 2, 0, { 0, 1,} }; -inline const NUMBER init_q_rat_min_long = { +inline const NUMBER init_q_rat_min_i32 = { 1, 1, 0, diff --git a/src/CalcManager/Ratpack/ratpak.h b/src/CalcManager/Ratpack/ratpak.h index 3ae06734..349569a6 100644 --- a/src/CalcManager/Ratpack/ratpak.h +++ b/src/CalcManager/Ratpack/ratpak.h @@ -17,15 +17,19 @@ // //----------------------------------------------------------------------------- +#include +#include #include "CalcErr.h" +#include // for memmove +#include // for SAL static constexpr uint32_t BASEXPWR = 31L;// Internal log2(BASEX) static constexpr uint32_t BASEX = 0x80000000; // Internal radix used in calculations, hope to raise // this to 2^32 after solving scaling problems with // overflow detection esp. in mul -typedef unsigned long MANTTYPE; -typedef unsigned __int64 TWO_MANTTYPE; +typedef uint32_t MANTTYPE; +typedef uint64_t TWO_MANTTYPE; enum eNUMOBJ_FMT { FMT_FLOAT, // returns floating point, or exponential if number is too big @@ -54,10 +58,10 @@ typedef enum eANGLE_TYPE ANGLE_TYPE; #pragma warning(disable:4200) // nonstandard extension used : zero-sized array in struct/union typedef struct _number { - long sign; // The sign of the mantissa, +1, or -1 - long cdigit; // The number of digits, or what passes for digits in the + int32_t sign; // The sign of the mantissa, +1, or -1 + int32_t cdigit; // The number of digits, or what passes for digits in the // radix being used. - long exp; // The offset of digits from the radix point + int32_t exp; // The offset of digits from the radix point // (decimal point in radix 10) MANTTYPE mant[]; // This is actually allocated as a continuation of the @@ -127,8 +131,8 @@ extern PRAT rat_max_exp; extern PRAT rat_min_exp; extern PRAT rat_max_fact; extern PRAT rat_min_fact; -extern PRAT rat_max_long; -extern PRAT rat_min_long; +extern PRAT rat_max_i32; +extern PRAT rat_min_i32; // DUPNUM Duplicates a number taking care of allocation and internals #define DUPNUM(a,b) destroynum(a);createnum( a, (b)->cdigit );_dupnum(a, b); @@ -148,6 +152,9 @@ extern PRAT rat_min_long; #define LOGNUM2(pnum) ((pnum)->cdigit+(pnum)->exp) #define LOGRAT2(prat) (LOGNUM2((prat)->pp)-LOGNUM2((prat)->pq)) +// SIGN returns the sign of the rational +#define SIGN(prat) ((prat)->pp->sign*(prat)->pq->sign) + #if defined( DEBUG_RATPAK ) //----------------------------------------------------------------------------- // @@ -208,7 +215,7 @@ _destroynum(x),(x)=nullptr // TRIMNUM ASSUMES the number is in radix form NOT INTERNAL BASEX!!! #define TRIMNUM(x, precision) if ( !g_ftrueinfinite ) { \ - long trim = (x)->cdigit - precision-g_ratio;\ + int32_t trim = (x)->cdigit - precision-g_ratio;\ if ( trim > 1 ) \ { \ memmove( (x)->mant, &((x)->mant[trim]), sizeof(MANTTYPE)*((x)->cdigit-trim) ); \ @@ -218,14 +225,14 @@ memmove( (x)->mant, &((x)->mant[trim]), sizeof(MANTTYPE)*((x)->cdigit-trim) ); \ } // TRIMTOP ASSUMES the number is in INTERNAL BASEX!!! #define TRIMTOP(x, precision) if ( !g_ftrueinfinite ) { \ - long trim = (x)->pp->cdigit - (precision/g_ratio) - 2;\ + int32_t trim = (x)->pp->cdigit - (precision/g_ratio) - 2;\ if ( trim > 1 ) \ { \ memmove( (x)->pp->mant, &((x)->pp->mant[trim]), sizeof(MANTTYPE)*((x)->pp->cdigit-trim) ); \ (x)->pp->cdigit -= trim; \ (x)->pp->exp += trim; \ } \ - trim = min((x)->pp->exp,(x)->pq->exp);\ + trim = std::min((x)->pp->exp,(x)->pq->exp);\ (x)->pp->exp -= trim;\ (x)->pq->exp -= trim;\ } @@ -246,8 +253,8 @@ memmove( (x)->pp->mant, &((x)->pp->mant[trim]), sizeof(MANTTYPE)*((x)->pp->cdigi DUPRAT(xx,*px); \ mulrat(&xx,*px, precision); \ createrat(pret); \ - pret->pp=longtonum( 0L, BASEX ); \ - pret->pq=longtonum( 0L, BASEX ); + pret->pp=i32tonum( 0L, BASEX ); \ + pret->pq=i32tonum( 0L, BASEX ); #define DESTROYTAYLOR() destroynum( n2 ); \ destroyrat( xx );\ @@ -294,7 +301,7 @@ extern bool g_ftrueinfinite; // set to true to allow infinite precision // don't use unless you know what you are doing // used to help decide when to stop calculating. -extern long g_ratio; // Internally calculated ratio of internal radix +extern int32_t g_ratio; // Internally calculated ratio of internal radix //----------------------------------------------------------------------------- // @@ -321,10 +328,10 @@ extern PNUMBER RatToNumber(_In_ PRAT prat, uint32_t radix, int32_t precision); // flattens a PRAT by converting it to a PNUMBER and back to a PRAT extern void flatrat(_Inout_ PRAT& prat, uint32_t radix, int32_t precision); -extern long numtolong(_In_ PNUMBER pnum, uint32_t radix ); -extern long rattolong(_In_ PRAT prat, uint32_t radix, int32_t precision); -ULONGLONG rattoUlonglong(_In_ PRAT prat, uint32_t radix, int32_t precision); -extern PNUMBER _createnum(_In_ ULONG size ); // returns an empty number structure with size digits +extern int32_t numtoi32(_In_ PNUMBER pnum, uint32_t radix ); +extern int32_t rattoi32(_In_ PRAT prat, uint32_t radix, int32_t precision); +uint64_t rattoUi64(_In_ PRAT prat, uint32_t radix, int32_t precision); +extern PNUMBER _createnum(_In_ uint32_t size ); // returns an empty number structure with size digits extern PNUMBER nRadixxtonum(_In_ PNUMBER a, uint32_t radix, int32_t precision); extern PNUMBER gcd(_In_ PNUMBER a, _In_ PNUMBER b ); extern PNUMBER StringToNumber(std::wstring_view numberString, uint32_t radix, int32_t precision); // takes a text representation of a number and returns a number. @@ -332,10 +339,10 @@ extern PNUMBER StringToNumber(std::wstring_view numberString, uint32_t radix, in // takes a text representation of a number as a mantissa with sign and an exponent with sign. extern PRAT StringToRat(bool mantissaIsNegative, std::wstring_view mantissa, bool exponentIsNegative, std::wstring_view exponent, uint32_t radix, int32_t precision); -extern PNUMBER longfactnum(long inlong, uint32_t radix); -extern PNUMBER longprodnum(long start, long stop, uint32_t radix); -extern PNUMBER longtonum(long inlong, uint32_t radix); -extern PNUMBER Ulongtonum(unsigned long inlong, uint32_t radix); +extern PNUMBER i32factnum(int32_t ini32, uint32_t radix); +extern PNUMBER i32prodnum(int32_t start, int32_t stop, uint32_t radix); +extern PNUMBER i32tonum(int32_t ini32, uint32_t radix); +extern PNUMBER Ui32tonum(uint32_t ini32, uint32_t radix); extern PNUMBER numtonRadixx(PNUMBER a, uint32_t radix); // creates a empty/undefined rational representation (p/q) @@ -393,8 +400,8 @@ extern void log10rat( _Inout_ PRAT *px, int32_t precision); // returns a new rat structure with the natural log of x->p/x->q extern void lograt( _Inout_ PRAT *px, int32_t precision); -extern PRAT longtorat( long inlong ); -extern PRAT Ulongtorat( unsigned long inulong ); +extern PRAT i32torat( int32_t ini32 ); +extern PRAT Ui32torat( uint32_t inui32 ); extern PRAT numtorat( _In_ PNUMBER pin, uint32_t radix); extern void sinhrat( _Inout_ PRAT *px, uint32_t radix, int32_t precision); @@ -423,19 +430,20 @@ extern void divnumx( _Inout_ PNUMBER *pa, _In_ PNUMBER b, int32_t precision); extern void divrat( _Inout_ PRAT *pa, _In_ PRAT b, int32_t precision); extern void fracrat( _Inout_ PRAT *pa , uint32_t radix, int32_t precision); extern void factrat( _Inout_ PRAT *pa, uint32_t radix, int32_t precision); -extern void modrat( _Inout_ PRAT *pa, _In_ PRAT b ); +extern void remrat(_Inout_ PRAT *pa, _In_ PRAT b); +extern void modrat(_Inout_ PRAT *pa, _In_ PRAT b); extern void gcdrat( _Inout_ PRAT *pa, int32_t precision); extern void intrat( _Inout_ PRAT *px, uint32_t radix, int32_t precision); extern void mulnum( _Inout_ PNUMBER *pa, _In_ PNUMBER b, uint32_t radix); extern void mulnumx( _Inout_ PNUMBER *pa, _In_ PNUMBER b ); extern void mulrat( _Inout_ PRAT *pa, _In_ PRAT b, int32_t precision); -extern void numpowlong( _Inout_ PNUMBER *proot, long power, uint32_t radix, int32_t precision); -extern void numpowlongx( _Inout_ PNUMBER *proot, long power ); +extern void numpowi32( _Inout_ PNUMBER *proot, int32_t power, uint32_t radix, int32_t precision); +extern void numpowi32x( _Inout_ PNUMBER *proot, int32_t power ); extern void orrat( _Inout_ PRAT *pa, _In_ PRAT b, uint32_t radix, int32_t precision); extern void powrat( _Inout_ PRAT *pa, _In_ PRAT b , uint32_t radix, int32_t precision); extern void powratNumeratorDenominator(_Inout_ PRAT *pa, _In_ PRAT b, uint32_t radix, int32_t precision); extern void powratcomp(_Inout_ PRAT *pa, _In_ PRAT b, uint32_t radix, int32_t precision); -extern void ratpowlong( _Inout_ PRAT *proot, long power, int32_t precision); +extern void ratpowi32( _Inout_ PRAT *proot, int32_t power, int32_t precision); extern void remnum( _Inout_ PNUMBER *pa, _In_ PNUMBER b, uint32_t radix); extern void rootrat( _Inout_ PRAT *pa, _In_ PRAT b , uint32_t radix, int32_t precision); extern void scale2pi( _Inout_ PRAT *px, uint32_t radix, int32_t precision); diff --git a/src/CalcManager/Ratpack/support.cpp b/src/CalcManager/Ratpack/support.cpp index f3b00d2f..1e6a9204 100644 --- a/src/CalcManager/Ratpack/support.cpp +++ b/src/CalcManager/Ratpack/support.cpp @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. //---------------------------------------------------------------------------- @@ -18,7 +18,9 @@ // //---------------------------------------------------------------------------- -#include "pch.h" +#include +#include // for memmove +#include // for wostream #include "ratpak.h" using namespace std; @@ -45,8 +47,8 @@ static int cbitsofprecision = 0; DUPNUM((v)->pq,(&(init_q_##v))); #define READRAWNUM(v) DUPNUM(v,(&(init_##v))) -#define INIT_AND_DUMP_RAW_NUM_IF_NULL(r, v) if (r == nullptr) { r = longtonum(v, BASEX); DUMPRAWNUM(v); } -#define INIT_AND_DUMP_RAW_RAT_IF_NULL(r, v) if (r == nullptr) { r = longtorat(v); DUMPRAWRAT(v); } +#define INIT_AND_DUMP_RAW_NUM_IF_NULL(r, v) if (r == nullptr) { r = i32tonum(v, BASEX); DUMPRAWNUM(v); } +#define INIT_AND_DUMP_RAW_RAT_IF_NULL(r, v) if (r == nullptr) { r = i32torat(v); DUMPRAWRAT(v); } static constexpr int RATIO_FOR_DECIMAL = 9; static constexpr int DECIMAL = 10; @@ -87,7 +89,7 @@ PRAT rat_exp= nullptr; PRAT rad_to_deg= nullptr; PRAT rad_to_grad= nullptr; PRAT rat_qword= nullptr; -PRAT rat_dword= nullptr; // unsigned max ulong +PRAT rat_dword= nullptr; // unsigned max ui32 PRAT rat_word= nullptr; PRAT rat_byte= nullptr; PRAT rat_360= nullptr; @@ -101,8 +103,8 @@ PRAT rat_max_exp= nullptr; PRAT rat_min_exp= nullptr; PRAT rat_max_fact = nullptr; PRAT rat_min_fact = nullptr; -PRAT rat_min_long= nullptr; // min signed long -PRAT rat_max_long= nullptr; // max signed long +PRAT rat_min_i32= nullptr; // min signed i32 +PRAT rat_max_i32= nullptr; // max signed i32 //---------------------------------------------------------------------------- // @@ -132,7 +134,7 @@ void ChangeConstants(uint32_t radix, int32_t precision) g_ratio += !g_ratio; destroyrat(rat_nRadix); - rat_nRadix=longtorat( radix ); + rat_nRadix=i32torat( radix ); // Check to see what we have to recalculate and what we don't if (cbitsofprecision < (g_ratio * static_cast(radix) * precision)) @@ -166,7 +168,7 @@ void ChangeConstants(uint32_t radix, int32_t precision) INIT_AND_DUMP_RAW_RAT_IF_NULL(rat_min_fact, -1000); DUPRAT(rat_smallest, rat_nRadix); - ratpowlong(&rat_smallest, -precision, precision); + ratpowi32(&rat_smallest, -precision, precision); DUPRAT(rat_negsmallest, rat_smallest); rat_negsmallest->pp->sign = -1; DUMPRAWRAT(rat_smallest); @@ -183,29 +185,29 @@ void ChangeConstants(uint32_t radix, int32_t precision) if (pt_eight_five == nullptr) { createrat(pt_eight_five); - pt_eight_five->pp = longtonum(85L, BASEX); - pt_eight_five->pq = longtonum(100L, BASEX); + pt_eight_five->pp = i32tonum(85L, BASEX); + pt_eight_five->pq = i32tonum(100L, BASEX); DUMPRAWRAT(pt_eight_five); } DUPRAT(rat_qword, rat_two); - numpowlong(&(rat_qword->pp), 64, BASEX, precision); + numpowi32(&(rat_qword->pp), 64, BASEX, precision); subrat(&rat_qword, rat_one, precision); DUMPRAWRAT(rat_qword); DUPRAT(rat_dword, rat_two); - numpowlong(&(rat_dword->pp), 32, BASEX, precision); + numpowi32(&(rat_dword->pp), 32, BASEX, precision); subrat(&rat_dword, rat_one, precision); DUMPRAWRAT(rat_dword); - DUPRAT(rat_max_long, rat_two); - numpowlong(&(rat_max_long->pp), 31, BASEX, precision); - DUPRAT(rat_min_long, rat_max_long); - subrat(&rat_max_long, rat_one, precision); // rat_max_long = 2^31 -1 - DUMPRAWRAT(rat_max_long); + DUPRAT(rat_max_i32, rat_two); + numpowi32(&(rat_max_i32->pp), 31, BASEX, precision); + DUPRAT(rat_min_i32, rat_max_i32); + subrat(&rat_max_i32, rat_one, precision); // rat_max_i32 = 2^31 -1 + DUMPRAWRAT(rat_max_i32); - rat_min_long->pp->sign *= -1; // rat_min_long = -2^31 - DUMPRAWRAT(rat_min_long); + rat_min_i32->pp->sign *= -1; // rat_min_i32 = -2^31 + DUMPRAWRAT(rat_min_i32); DUPRAT(rat_min_exp, rat_max_exp); rat_min_exp->pp->sign *= -1; @@ -215,7 +217,7 @@ void ChangeConstants(uint32_t radix, int32_t precision) // Apparently when dividing 180 by pi, another (internal) digit of // precision is needed. - long extraPrecision = precision + g_ratio; + int32_t extraPrecision = precision + g_ratio; DUPRAT(pi, rat_half); asinrat(&pi, radix, extraPrecision); mulrat(&pi, rat_six, extraPrecision); @@ -253,12 +255,12 @@ void ChangeConstants(uint32_t radix, int32_t precision) destroyrat(rad_to_deg); - rad_to_deg = longtorat(180L); + rad_to_deg = i32torat(180L); divrat(&rad_to_deg, pi, extraPrecision); DUMPRAWRAT(rad_to_deg); destroyrat(rad_to_grad); - rad_to_grad = longtorat(200L); + rad_to_grad = i32torat(200L); divrat(&rad_to_grad, pi, extraPrecision); DUMPRAWRAT(rad_to_grad); } @@ -267,7 +269,7 @@ void ChangeConstants(uint32_t radix, int32_t precision) _readconstants(); DUPRAT(rat_smallest, rat_nRadix); - ratpowlong(&rat_smallest, -precision, precision); + ratpowi32(&rat_smallest, -precision, precision); DUPRAT(rat_negsmallest, rat_smallest); rat_negsmallest->pp->sign = -1; } @@ -296,7 +298,7 @@ void intrat( PRAT *px, uint32_t radix, int32_t precision) // Subtract the fractional part of the rational PRAT pret = nullptr; DUPRAT(pret,*px); - modrat( &pret, rat_one ); + remrat( &pret, rat_one ); subrat( px, pret, precision); destroyrat( pret ); @@ -333,7 +335,7 @@ bool rat_equ( PRAT a, PRAT b, int32_t precision) // // FUNCTION: rat_ge // -// ARGUMENTS: PRAT a, PRAT b and long precision +// ARGUMENTS: PRAT a, PRAT b and int32_t precision // // RETURN: true if a is greater than or equal to b // @@ -348,8 +350,7 @@ bool rat_ge( PRAT a, PRAT b, int32_t precision) b->pp->sign *= -1; addrat( &rattmp, b, precision); b->pp->sign *= -1; - bool bret = ( zernum( rattmp->pp ) || - rattmp->pp->sign * rattmp->pq->sign == 1 ); + bool bret = ( zernum( rattmp->pp ) || SIGN(rattmp) == 1 ); destroyrat( rattmp ); return( bret ); } @@ -374,8 +375,7 @@ bool rat_gt( PRAT a, PRAT b, int32_t precision) b->pp->sign *= -1; addrat( &rattmp, b, precision); b->pp->sign *= -1; - bool bret = ( !zernum( rattmp->pp ) && - rattmp->pp->sign * rattmp->pq->sign == 1 ); + bool bret = ( !zernum( rattmp->pp ) && SIGN(rattmp) == 1 ); destroyrat( rattmp ); return( bret ); } @@ -384,7 +384,7 @@ bool rat_gt( PRAT a, PRAT b, int32_t precision) // // FUNCTION: rat_le // -// ARGUMENTS: PRAT a, PRAT b and long precision +// ARGUMENTS: PRAT a, PRAT b and int32_t precision // // RETURN: true if a is less than or equal to b // @@ -400,8 +400,7 @@ bool rat_le( PRAT a, PRAT b, int32_t precision) b->pp->sign *= -1; addrat( &rattmp, b, precision); b->pp->sign *= -1; - bool bret = ( zernum( rattmp->pp ) || - rattmp->pp->sign * rattmp->pq->sign == -1 ); + bool bret = ( zernum( rattmp->pp ) || SIGN(rattmp) == -1 ); destroyrat( rattmp ); return( bret ); } @@ -411,7 +410,7 @@ bool rat_le( PRAT a, PRAT b, int32_t precision) // // FUNCTION: rat_lt // -// ARGUMENTS: PRAT a, PRAT b and long precision +// ARGUMENTS: PRAT a, PRAT b and int32_t precision // // RETURN: true if a is less than b // @@ -426,8 +425,7 @@ bool rat_lt( PRAT a, PRAT b, int32_t precision) b->pp->sign *= -1; addrat( &rattmp, b, precision); b->pp->sign *= -1; - bool bret = ( !zernum( rattmp->pp ) && - rattmp->pp->sign * rattmp->pq->sign == -1 ); + bool bret = ( !zernum( rattmp->pp ) && SIGN(rattmp) == -1 ); destroyrat( rattmp ); return( bret ); } @@ -475,7 +473,7 @@ void scale( PRAT *px, PRAT scalefact, uint32_t radix, int32_t precision ) // Logscale is a quick way to tell how much extra precision is needed for // scaling by scalefact. - long logscale = g_ratio * ( (pret->pp->cdigit+pret->pp->exp) - + int32_t logscale = g_ratio * ( (pret->pp->cdigit+pret->pp->exp) - (pret->pq->cdigit+pret->pq->exp) ); if ( logscale > 0 ) { @@ -510,7 +508,7 @@ void scale2pi( PRAT *px, uint32_t radix, int32_t precision ) // Logscale is a quick way to tell how much extra precision is needed for // scaling by 2 pi. - long logscale = g_ratio * ( (pret->pp->cdigit+pret->pp->exp) - + int32_t logscale = g_ratio * ( (pret->pp->cdigit+pret->pp->exp) - (pret->pq->cdigit+pret->pq->exp) ); if ( logscale > 0 ) { @@ -652,15 +650,15 @@ void _readconstants( void ) READRAWRAT(rat_min_exp); READRAWRAT(rat_max_fact); READRAWRAT(rat_min_fact); - READRAWRAT(rat_min_long); - READRAWRAT(rat_max_long); + READRAWRAT(rat_min_i32); + READRAWRAT(rat_max_i32); } //--------------------------------------------------------------------------- // // FUNCTION: trimit // -// ARGUMENTS: PRAT *px, long precision +// ARGUMENTS: PRAT *px, int32_t precision // // // DESCRIPTION: Chops off digits from rational numbers to avoid time @@ -681,7 +679,7 @@ void trimit( PRAT *px, int32_t precision) { if ( !g_ftrueinfinite ) { - long trim; + int32_t trim; PNUMBER pp=(*px)->pp; PNUMBER pq=(*px)->pq; trim = g_ratio * (min((pp->cdigit+pp->exp),(pq->cdigit+pq->exp))-1) - precision; diff --git a/src/CalcManager/Ratpack/trans.cpp b/src/CalcManager/Ratpack/trans.cpp index 5b46a936..3706d44d 100644 --- a/src/CalcManager/Ratpack/trans.cpp +++ b/src/CalcManager/Ratpack/trans.cpp @@ -14,7 +14,6 @@ // //---------------------------------------------------------------------------- -#include "pch.h" #include "ratpak.h" @@ -168,12 +167,12 @@ void _cosrat( PRAT *px, uint32_t radix, int32_t precision) destroynum(pret->pp); destroynum(pret->pq); - pret->pp=longtonum( 1L, radix); - pret->pq=longtonum( 1L, radix); + pret->pp=i32tonum( 1L, radix); + pret->pq=i32tonum( 1L, radix); DUPRAT(thisterm,pret) - n2=longtonum(0L, radix); + n2=i32tonum(0L, radix); xx->pp->sign *= -1; do { diff --git a/src/CalcManager/Ratpack/transh.cpp b/src/CalcManager/Ratpack/transh.cpp index 8a835341..85c27f8b 100644 --- a/src/CalcManager/Ratpack/transh.cpp +++ b/src/CalcManager/Ratpack/transh.cpp @@ -14,7 +14,6 @@ // // //----------------------------------------------------------------------------- -#include "pch.h" #include "ratpak.h" @@ -159,12 +158,12 @@ void _coshrat( PRAT *px, uint32_t radix, int32_t precision) CREATETAYLOR(); - pret->pp=longtonum( 1L, radix); - pret->pq=longtonum( 1L, radix); + pret->pp=i32tonum( 1L, radix); + pret->pq=i32tonum( 1L, radix); DUPRAT(thisterm,pret) - n2=longtonum(0L, radix); + n2=i32tonum(0L, radix); do { NEXTTERM(xx,INC(n2) DIVNUM(n2) INC(n2) DIVNUM(n2), precision); diff --git a/src/CalcManager/UnitConverter.cpp b/src/CalcManager/UnitConverter.cpp index 0548719a..7bfc4817 100644 --- a/src/CalcManager/UnitConverter.cpp +++ b/src/CalcManager/UnitConverter.cpp @@ -1,7 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "pch.h" +#include +#include +#include // for std::sort #include "Command.h" #include "UnitConverter.h" @@ -63,7 +65,8 @@ UnitConverter::UnitConverter(_In_ const shared_ptr& dataLo unquoteConversions[L"{sc}"] = L';'; unquoteConversions[L"{lb}"] = LEFTESCAPECHAR; unquoteConversions[L"{rb}"] = RIGHTESCAPECHAR; - Reset(); + ClearValues(); + ResetCategoriesAndRatios(); } void UnitConverter::Initialize() @@ -75,7 +78,7 @@ bool UnitConverter::CheckLoad() { if (m_categories.empty()) { - Reset(); + ResetCategoriesAndRatios(); } return !m_categories.empty(); } @@ -152,7 +155,6 @@ void UnitConverter::SetCurrentUnitTypes(const Unit& fromType, const Unit& toType Calculate(); UpdateCurrencySymbols(); - UpdateViewModel(); } /// @@ -336,7 +338,8 @@ wstring UnitConverter::Serialize() /// wstring holding the serialized data. If it does not have expected number of parameters, we will ignore it void UnitConverter::DeSerialize(const wstring& serializedData) { - Reset(); + ClearValues(); + ResetCategoriesAndRatios(); if (serializedData.empty()) { @@ -403,12 +406,30 @@ void UnitConverter::RestoreUserPreferences(const wstring& userPreferences) } vector outerTokens = StringToVector(userPreferences, L"|"); - if (outerTokens.size() == 3) + if (outerTokens.size() != 3) { - m_fromType = StringToUnit(outerTokens[0]); - m_toType = StringToUnit(outerTokens[1]); - m_currentCategory = StringToCategory(outerTokens[2]); + return; } + + auto fromType = StringToUnit(outerTokens[0]); + auto toType = StringToUnit(outerTokens[1]); + m_currentCategory = StringToCategory(outerTokens[2]); + + // Only restore from the saved units if they are valid in the current available units. + auto itr = m_categoryToUnits.find(m_currentCategory); + if (itr != m_categoryToUnits.end()) + { + const auto& curUnits = itr->second; + if (find(curUnits.begin(), curUnits.end(), fromType) != curUnits.end()) + { + m_fromType = fromType; + } + if (find(curUnits.begin(), curUnits.end(), toType) != curUnits.end()) + { + m_toType = toType; + } + } + } /// @@ -615,7 +636,7 @@ void UnitConverter::SendCommand(Command command) clearFront = false; clearBack = false; ClearValues(); - Reset(); + ResetCategoriesAndRatios(); break; default: @@ -634,8 +655,6 @@ void UnitConverter::SendCommand(Command command) } Calculate(); - - UpdateViewModel(); } /// @@ -824,19 +843,16 @@ vector> UnitConverter::CalculateSuggested() returnVector.push_back(whimsicalReturnVector.at(0)); } - // - return returnVector; } /// -/// Resets the converter to its initial state +/// Resets categories and ratios /// -void UnitConverter::Reset() +void UnitConverter::ResetCategoriesAndRatios() { m_categories = m_dataLoader->LoadOrderedCategories(); - ClearValues(); m_switchedActive = false; if (m_categories.empty()) @@ -881,7 +897,6 @@ void UnitConverter::Reset() } InitializeSelectedUnits(); - Calculate(); } /// @@ -972,11 +987,21 @@ bool UnitConverter::AnyUnitIsEmpty() /// void UnitConverter::Calculate() { - unordered_map conversionTable = m_ratioMap[m_fromType]; - double returnValue = stod(m_currentDisplay); - if (AnyUnitIsEmpty() || (conversionTable[m_toType].ratio == 1.0 && conversionTable[m_toType].offset == 0.0)) + if (AnyUnitIsEmpty()) { m_returnDisplay = m_currentDisplay; + m_returnHasDecimal = m_currentHasDecimal; + TrimString(m_returnDisplay); + UpdateViewModel(); + return; + } + + unordered_map conversionTable = m_ratioMap[m_fromType]; + double returnValue = stod(m_currentDisplay); + if (conversionTable[m_toType].ratio == 1.0 && conversionTable[m_toType].offset == 0.0) + { + m_returnDisplay = m_currentDisplay; + m_returnHasDecimal = m_currentHasDecimal; TrimString(m_returnDisplay); } else @@ -1015,9 +1040,9 @@ void UnitConverter::Calculate() m_returnDisplay = returnString; TrimString(m_returnDisplay); } + m_returnHasDecimal = (m_returnDisplay.find(L'.') != m_returnDisplay.npos); } - - m_returnHasDecimal = (m_returnDisplay.find(L'.') != m_returnDisplay.npos); + UpdateViewModel(); } /// diff --git a/src/CalcManager/UnitConverter.h b/src/CalcManager/UnitConverter.h index 4e130d12..4c77f8aa 100644 --- a/src/CalcManager/UnitConverter.h +++ b/src/CalcManager/UnitConverter.h @@ -1,8 +1,14 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #pragma once +#include +#include +#include +#include // for SAL +#include // for std::shared_ptr + namespace UnitConversionManager { enum class Command; @@ -195,6 +201,8 @@ namespace UnitConversionManager virtual void SetViewModelCallback(_In_ const std::shared_ptr& newCallback) = 0; virtual void SetViewModelCurrencyCallback(_In_ const std::shared_ptr& newCallback) = 0; virtual concurrency::task> RefreshCurrencyRatios() = 0; + virtual void Calculate() = 0; + virtual void ResetCategoriesAndRatios() = 0; }; class UnitConverter : public IUnitConverter, public std::enable_shared_from_this @@ -218,6 +226,8 @@ namespace UnitConversionManager void SetViewModelCallback(_In_ const std::shared_ptr& newCallback) override; void SetViewModelCurrencyCallback(_In_ const std::shared_ptr& newCallback) override; concurrency::task> RefreshCurrencyRatios() override; + void Calculate() override; + void ResetCategoriesAndRatios() override; // IUnitConverter static std::vector StringToVector(const std::wstring& w, const wchar_t * delimiter, bool addRemainder = false); @@ -228,9 +238,7 @@ namespace UnitConversionManager bool CheckLoad(); double Convert(double value, ConversionData conversionData); std::vector> CalculateSuggested(); - void Reset(); void ClearValues(); - void Calculate(); void TrimString(std::wstring& input); void InitializeSelectedUnits(); std::wstring RoundSignificant(double num, int numSignificant); diff --git a/src/CalcManager/pch.cpp b/src/CalcManager/pch.cpp index 1da170eb..8ca9987d 100644 --- a/src/CalcManager/pch.cpp +++ b/src/CalcManager/pch.cpp @@ -1,4 +1,6 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "pch.h" +// Intentionally do not include the pch.h here. For projects that don't +// use precompiled headers, including the header here would force unnecessary compilation. +// The pch will be included through forced include. diff --git a/src/CalcManager/pch.h b/src/CalcManager/pch.h index 4690713c..e66e1a38 100644 --- a/src/CalcManager/pch.h +++ b/src/CalcManager/pch.h @@ -1,24 +1,22 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #pragma once -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif +// The CalcManager project should be able to be compiled with or without a precompiled header +// in - order to support other toolchains besides MSVC. When adding new system headers, make sure +// that the relevant source file includes all headers it needs, but then also add the system headers +// here so that MSVC users see the performance benefit. -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include diff --git a/src/CalcManager/targetver.h b/src/CalcManager/targetver.h deleted file mode 100644 index 221efabb..00000000 --- a/src/CalcManager/targetver.h +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -// Including SDKDDKVer.h defines the highest available Windows platform. - -// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and -// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. - -#include diff --git a/src/CalcViewModel/ApplicationViewModel.cpp b/src/CalcViewModel/ApplicationViewModel.cpp index 4df5bac3..5033080b 100644 --- a/src/CalcViewModel/ApplicationViewModel.cpp +++ b/src/CalcViewModel/ApplicationViewModel.cpp @@ -32,14 +32,10 @@ using namespace Windows::UI::Xaml::Data; using namespace Windows::UI::Xaml::Input; using namespace Windows::UI::Xaml::Media; -namespace CalculatorApp::ViewModel::ApplicationViewModelProperties +namespace { - StringReference Mode(L"Mode"); - StringReference PreviousMode(L"PreviousMode"); - StringReference ClearMemoryVisibility(L"ClearMemoryVisibility"); - StringReference AppBarVisibility(L"AppBarVisibility"); - StringReference CategoryName(L"CategoryName"); - StringReference Categories(L"Categories"); + StringReference CategoriesPropertyName(L"Categories"); + StringReference ClearMemoryVisibilityPropertyName(L"ClearMemoryVisibility"); } ApplicationViewModel::ApplicationViewModel() : @@ -60,7 +56,7 @@ void ApplicationViewModel::Mode::set(ViewMode value) PreviousMode = m_mode; m_mode = value; OnModeChanged(); - RaisePropertyChanged(ApplicationViewModelProperties::Mode); + RaisePropertyChanged(ModePropertyName); } } @@ -69,7 +65,7 @@ void ApplicationViewModel::Categories::set(IObservableVector^ if (m_categories != value) { m_categories = value; - RaisePropertyChanged(ApplicationViewModelProperties::Categories); + RaisePropertyChanged(CategoriesPropertyName); } } @@ -163,11 +159,10 @@ void ApplicationViewModel::OnModeChanged() // // Save the changed mode, so that the new window launches in this mode. // Don't save until after we have adjusted to the new mode, so we don't save a mode that fails to load. - ApplicationData::Current->LocalSettings->Values->Insert(ApplicationViewModelProperties::Mode, NavCategory::Serialize(m_mode)); + ApplicationData::Current->LocalSettings->Values->Insert(ModePropertyName, NavCategory::Serialize(m_mode)); TraceLogger::GetInstance().LogModeChangeEnd(m_mode, ApplicationView::GetApplicationViewIdForWindow(CoreWindow::GetForCurrentThread())); - RaisePropertyChanged(ApplicationViewModelProperties::ClearMemoryVisibility); - RaisePropertyChanged(ApplicationViewModelProperties::AppBarVisibility); + RaisePropertyChanged(ClearMemoryVisibilityPropertyName); } void ApplicationViewModel::OnCopyCommand(Object^ parameter) @@ -192,7 +187,7 @@ void ApplicationViewModel::OnPasteCommand(Object^ parameter) { ConverterViewModel->OnPasteCommand(parameter); } - else + else if (NavCategory::IsCalculatorViewMode(m_mode)) { CalculatorViewModel->OnPasteCommand(parameter); } diff --git a/src/CalcViewModel/ApplicationViewModel.h b/src/CalcViewModel/ApplicationViewModel.h index a8d459f7..74567ca1 100644 --- a/src/CalcViewModel/ApplicationViewModel.h +++ b/src/CalcViewModel/ApplicationViewModel.h @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #pragma once @@ -11,16 +11,6 @@ namespace CalculatorApp { namespace ViewModel { - namespace ApplicationViewModelProperties - { - extern Platform::StringReference Mode; - extern Platform::StringReference PreviousMode; - extern Platform::StringReference ClearMemoryVisibility; - extern Platform::StringReference AppBarVisibility; - extern Platform::StringReference CategoryName; - extern Platform::StringReference Categories; - } - [Windows::UI::Xaml::Data::Bindable] public ref class ApplicationViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged { @@ -32,9 +22,9 @@ namespace CalculatorApp OBSERVABLE_OBJECT(); OBSERVABLE_PROPERTY_RW(StandardCalculatorViewModel^, CalculatorViewModel); OBSERVABLE_PROPERTY_RW(DateCalculatorViewModel^, DateCalcViewModel); - OBSERVABLE_PROPERTY_RW(CalculatorApp::ViewModel::UnitConverterViewModel^, ConverterViewModel); + OBSERVABLE_PROPERTY_RW(UnitConverterViewModel^, ConverterViewModel); OBSERVABLE_PROPERTY_RW(CalculatorApp::Common::ViewMode, PreviousMode); - OBSERVABLE_PROPERTY_RW(Platform::String^, CategoryName); + OBSERVABLE_NAMED_PROPERTY_RW(Platform::String^, CategoryName); COMMAND_FOR_METHOD(CopyCommand, ApplicationViewModel::OnCopyCommand); COMMAND_FOR_METHOD(PasteCommand, ApplicationViewModel::OnPasteCommand); @@ -48,6 +38,13 @@ namespace CalculatorApp void set(CalculatorApp::Common::ViewMode value); } + static property Platform::String^ ModePropertyName + { + Platform::String^ get() + { + return Platform::StringReference(L"Mode"); + } + } property Windows::Foundation::Collections::IObservableVector^ Categories { @@ -69,16 +66,6 @@ namespace CalculatorApp } } - property Windows::UI::Xaml::Visibility AppBarVisibility - { - Windows::UI::Xaml::Visibility get() - { - return CalculatorApp::Common::NavCategory::IsCalculatorViewMode(Mode) - ? Windows::UI::Xaml::Visibility::Visible - : Windows::UI::Xaml::Visibility::Collapsed; - } - } - private: bool TryRecoverFromNavigationModeFailure(); diff --git a/src/CalcViewModel/Common/Automation/NarratorNotifier.cpp b/src/CalcViewModel/Common/Automation/NarratorNotifier.cpp index 4dc48074..b17aaba4 100644 --- a/src/CalcViewModel/Common/Automation/NarratorNotifier.cpp +++ b/src/CalcViewModel/Common/Automation/NarratorNotifier.cpp @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. // Implementation of the NarratorNotifier class. diff --git a/src/CalcViewModel/Common/CalculatorDisplay.cpp b/src/CalcViewModel/Common/CalculatorDisplay.cpp index cd531e01..4da98129 100644 --- a/src/CalcViewModel/Common/CalculatorDisplay.cpp +++ b/src/CalcViewModel/Common/CalculatorDisplay.cpp @@ -36,7 +36,7 @@ void CalculatorDisplay::SetPrimaryDisplay(_In_ const wstring& displayStringValue } } -void CalculatorDisplay::SetParenDisplayText(_In_ const std::wstring& parenthesisCount) +void CalculatorDisplay::SetParenthesisNumber(_In_ unsigned int parenthesisCount) { if (m_callbackReference != nullptr) { diff --git a/src/CalcViewModel/Common/CalculatorDisplay.h b/src/CalcViewModel/Common/CalculatorDisplay.h index 9ff06a6e..877bdf06 100644 --- a/src/CalcViewModel/Common/CalculatorDisplay.h +++ b/src/CalcViewModel/Common/CalculatorDisplay.h @@ -21,7 +21,7 @@ namespace CalculatorApp void SetExpressionDisplay(_Inout_ std::shared_ptr>> const &tokens, _Inout_ std::shared_ptr>> const &commands) override; void SetMemorizedNumbers(_In_ const std::vector& memorizedNumbers) override; void OnHistoryItemAdded(_In_ unsigned int addedItemIndex) override; - void SetParenDisplayText(_In_ const std::wstring& parenthesisCount) override; + void SetParenthesisNumber(_In_ unsigned int parenthesisCount) override; void OnNoRightParenAdded() override; void MaxDigitsReached() override; void BinaryOperatorReceived() override; diff --git a/src/CalcViewModel/Common/CopyPasteManager.cpp b/src/CalcViewModel/Common/CopyPasteManager.cpp index 00f13b52..6d6807ba 100644 --- a/src/CalcViewModel/Common/CopyPasteManager.cpp +++ b/src/CalcViewModel/Common/CopyPasteManager.cpp @@ -15,17 +15,19 @@ using namespace Windows::Foundation; using namespace Windows::System; using namespace Windows::ApplicationModel::DataTransfer; -unsigned long long maxOperandNumber; - String^ CopyPasteManager::supportedFormats[] = { StandardDataFormats::Text }; -constexpr wstring_view c_validCharacterSet{ L"0123456789()+-*/.abcdefABCDEF" }; +static constexpr wstring_view c_validCharacterSet{ L"0123456789()+-*/.abcdefABCDEF" }; + +// The below values can not be "constexpr"-ed, +// as both wstring_view and wchar[] can not be concatenated // [\s\x85] means white-space characters static const wstring c_wspc = L"[\\s\\x85]*"; static const wstring c_wspcLParens = c_wspc + L"[(]*" + c_wspc; +static const wstring c_wspcLParenSigned = c_wspc + L"([-+]?[(])*" + c_wspc; static const wstring c_wspcRParens = c_wspc + L"[)]*" + c_wspc; static const wstring c_signedDecFloat = L"[-+]?\\d*(\\d|[.])\\d*"; @@ -44,8 +46,8 @@ static const array standardModePatterns = }; static const array scientificModePatterns = { - wregex(c_wspcLParens + c_signedDecFloat + c_wspcRParens), - wregex(c_wspcLParens + c_signedDecFloat + L"[e]([+]|[-])+\\d+" + c_wspcRParens) + wregex(L"(" + c_wspc + L"[-+]?)|(" + c_wspcLParenSigned + L")" + c_signedDecFloat + c_wspcRParens), + wregex(L"(" + c_wspc + L"[-+]?)|(" + c_wspcLParenSigned + L")" + c_signedDecFloat + L"[e]([+]|[-])+\\d+" + c_wspcRParens) }; static const array, 4> programmerModePatterns = { { @@ -102,19 +104,16 @@ task CopyPasteManager::GetStringToPaste(ViewMode mode, CategoryGroupTyp int CopyPasteManager::ClipboardTextFormat() { - int result = -1; - - auto dataPackageView = Clipboard::GetContent(); + const auto dataPackageView = Clipboard::GetContent(); for (int i = 0; i < RTL_NUMBER_OF(supportedFormats); i++) { if (dataPackageView->Contains(supportedFormats[i])) { - result = i; - break; + return i; } } - return result; + return -1; } String^ CopyPasteManager::ValidatePasteExpression(String^ pastedText, ViewMode mode, int programmerNumberBase, int bitLengthType) @@ -267,13 +266,8 @@ bool CopyPasteManager::ExpressionRegExMatch(vector operands, ViewMode m return false; } - bool expMatched = true; vector patterns{}; - - pair operandLimits = GetMaxOperandLengthAndValue(mode, modeType, programmerNumberBase, bitLengthType); - size_t maxOperandLength = operandLimits.first; - uint64_t maxOperandValue = operandLimits.second; - + if (mode == ViewMode::Standard) { patterns.assign(standardModePatterns.begin(), standardModePatterns.end()); @@ -291,11 +285,14 @@ bool CopyPasteManager::ExpressionRegExMatch(vector operands, ViewMode m patterns.assign(unitConverterPatterns.begin(), unitConverterPatterns.end()); } - for (const wstring& operand : operands) + const auto [maxOperandLength, maxOperandValue] = GetMaxOperandLengthAndValue(mode, modeType, programmerNumberBase, bitLengthType); + bool expMatched = true; + + for (const auto& operand : operands) { // Each operand only needs to match one of the available patterns. bool operandMatched = false; - for (const wregex& pattern : patterns) + for (const auto& pattern : patterns) { operandMatched = operandMatched || regex_match(operand, pattern); } @@ -304,7 +301,7 @@ bool CopyPasteManager::ExpressionRegExMatch(vector operands, ViewMode m { // Remove characters that are valid in the expression but we do not want to include in length calculations // or which will break conversion from string-to-ULL. - wstring operandValue = SanitizeOperand(operand); + const wstring operandValue = SanitizeOperand(operand); // If an operand exceeds the maximum length allowed, break and return. if (OperandLength(operandValue, mode, modeType, programmerNumberBase) > maxOperandLength) @@ -340,16 +337,16 @@ bool CopyPasteManager::ExpressionRegExMatch(vector operands, ViewMode m pair CopyPasteManager::GetMaxOperandLengthAndValue(ViewMode mode, CategoryGroupType modeType, int programmerNumberBase, int bitLengthType) { - size_t maxLength = 0; - uint64_t maxValue = 0; - + constexpr size_t defaultMaxOperandLength = 0; + constexpr uint64_t defaultMaxValue = 0; + if (mode == ViewMode::Standard) { - maxLength = MaxStandardOperandLength; + return make_pair(MaxStandardOperandLength, defaultMaxValue); } else if (mode == ViewMode::Scientific) { - maxLength = MaxScientificOperandLength; + return make_pair(MaxScientificOperandLength, defaultMaxValue); } else if (mode == ViewMode::Programmer) { @@ -389,20 +386,22 @@ pair CopyPasteManager::GetMaxOperandLengthAndValue(ViewMode mo unsigned int signBit = (programmerNumberBase == DecBase) ? 1 : 0; - maxLength = (size_t)ceil((bitLength - signBit) / bitsPerDigit); - maxValue = UINT64_MAX >> (MaxProgrammerBitLength - (bitLength - signBit)); + const auto maxLength = static_cast(ceil((bitLength - signBit) / bitsPerDigit)); + const uint64_t maxValue = UINT64_MAX >> (MaxProgrammerBitLength - (bitLength - signBit)); + + return make_pair(maxLength, maxValue); } else if (modeType == CategoryGroupType::Converter) { - maxLength = MaxConverterInputLength; + return make_pair(MaxConverterInputLength, defaultMaxValue); } - return make_pair(maxLength, maxValue); + return make_pair(defaultMaxOperandLength, defaultMaxValue); } wstring CopyPasteManager::SanitizeOperand(const wstring& operand) { - wchar_t unWantedChars[] = { L'\'', L'_', L'`', L'(', L')', L'-' }; + wchar_t unWantedChars[] = { L'\'', L'_', L'`', L'(', L')', L'-', L'+' }; return Utils::RemoveUnwantedCharsFromWstring(operand, unWantedChars, static_cast(size(unWantedChars))); } @@ -416,8 +415,7 @@ bool CopyPasteManager::TryOperandToULL(const wstring& operand, int numberBase, u return false; } - // Default to base10 - int intBase = 10; + int intBase; switch (numberBase) { case HexBase: @@ -429,6 +427,7 @@ bool CopyPasteManager::TryOperandToULL(const wstring& operand, int numberBase, u case BinBase: intBase = 2; break; + default: case DecBase: intBase = 10; break; @@ -440,11 +439,11 @@ bool CopyPasteManager::TryOperandToULL(const wstring& operand, int numberBase, u result = stoull(operand, &size, intBase); return true; } - catch (invalid_argument) + catch (const invalid_argument&) { // Do nothing } - catch (out_of_range) + catch (const out_of_range&) { // Do nothing } @@ -452,35 +451,28 @@ bool CopyPasteManager::TryOperandToULL(const wstring& operand, int numberBase, u return false; } -size_t CopyPasteManager::OperandLength(wstring operand, ViewMode mode, CategoryGroupType modeType, int programmerNumberBase) -{ - size_t len = 0; - if (mode == ViewMode::Standard || mode == ViewMode::Scientific) - { - len = StandardScientificOperandLength(operand); - } - else if (mode == ViewMode::Programmer) - { - len = ProgrammerOperandLength(operand, programmerNumberBase); - } - else if (modeType == CategoryGroupType::Converter) - { - len = operand.length(); +size_t CopyPasteManager::OperandLength(const wstring& operand, ViewMode mode, CategoryGroupType modeType, int programmerNumberBase) +{ + if (modeType == CategoryGroupType::Converter) { + return operand.length(); } - return len; + switch(mode) { + case ViewMode::Standard: + case ViewMode::Scientific: + return StandardScientificOperandLength(operand); + + case ViewMode::Programmer: + return ProgrammerOperandLength(operand, programmerNumberBase); + + default: + return 0; + } } -size_t CopyPasteManager::StandardScientificOperandLength(wstring operand) -{ - bool hasDecimal = false; - for (size_t i = 0; i < operand.length(); i++) - { - if (operand[i] == L'.') - { - hasDecimal = true; - } - } +size_t CopyPasteManager::StandardScientificOperandLength(const wstring& operand) +{ + const bool hasDecimal = operand.find('.') != wstring::npos; if (hasDecimal) { @@ -502,8 +494,7 @@ size_t CopyPasteManager::StandardScientificOperandLength(wstring operand) size_t CopyPasteManager::ProgrammerOperandLength(const wstring& operand, int numberBase) { - size_t len = operand.length(); - + vector prefixes{}; vector suffixes{}; switch (numberBase) @@ -524,7 +515,7 @@ size_t CopyPasteManager::ProgrammerOperandLength(const wstring& operand, int num break; default: // No defined prefixes/suffixes - break; + return 0; } // UInt suffixes are common across all modes @@ -534,9 +525,11 @@ size_t CopyPasteManager::ProgrammerOperandLength(const wstring& operand, int num wstring operandUpper = operand; transform(operandUpper.begin(), operandUpper.end(), operandUpper.begin(), towupper); + size_t len = operand.length(); + // Detect if there is a suffix and subtract its length // Check suffixes first to allow e.g. "0b" to result in length 1 (value 0), rather than length 0 (no value). - for (const wstring& suffix : suffixes) + for (const auto& suffix : suffixes) { if (len < suffix.length()) { @@ -551,7 +544,7 @@ size_t CopyPasteManager::ProgrammerOperandLength(const wstring& operand, int num } // Detect if there is a prefix and subtract its length - for (const wstring& prefix : prefixes) + for (const auto& prefix : prefixes) { if (len < prefix.length()) { diff --git a/src/CalcViewModel/Common/CopyPasteManager.h b/src/CalcViewModel/Common/CopyPasteManager.h index 9a886154..9d6fd669 100644 --- a/src/CalcViewModel/Common/CopyPasteManager.h +++ b/src/CalcViewModel/Common/CopyPasteManager.h @@ -13,15 +13,14 @@ namespace CalculatorUnitTests namespace CalculatorApp { - -#define QwordType 1 -#define DwordType 2 -#define WordType 3 -#define ByteType 4 -#define HexBase 5 -#define DecBase 6 -#define OctBase 7 -#define BinBase 8 + inline constexpr auto QwordType = 1; + inline constexpr auto DwordType = 2; + inline constexpr auto WordType = 3; + inline constexpr auto ByteType = 4; + inline constexpr auto HexBase = 5; + inline constexpr auto DecBase = 6; + inline constexpr auto OctBase = 7; + inline constexpr auto BinBase = 8; class CopyPasteManager { @@ -55,8 +54,8 @@ namespace CalculatorApp static std::pair GetMaxOperandLengthAndValue(CalculatorApp::Common::ViewMode mode, CalculatorApp::Common::CategoryGroupType modeType, int programmerNumberBase = -1, int bitLengthType = -1); static std::wstring SanitizeOperand(const std::wstring& operand); static bool TryOperandToULL(const std::wstring& operand, int numberBase, unsigned long long int& result); - static size_t OperandLength(std::wstring operand, CalculatorApp::Common::ViewMode mode, CalculatorApp::Common::CategoryGroupType modeType, int programmerNumberBase = -1); - static size_t StandardScientificOperandLength(std::wstring operand); + static size_t OperandLength(const std::wstring& operand, CalculatorApp::Common::ViewMode mode, CalculatorApp::Common::CategoryGroupType modeType, int programmerNumberBase = -1); + static size_t StandardScientificOperandLength(const std::wstring& operand); static size_t ProgrammerOperandLength(const std::wstring& operand, int numberBase); static std::wstring RemoveUnwantedCharsFromWstring(const std::wstring& input); diff --git a/src/CalcViewModel/Common/DateCalculator.h b/src/CalcViewModel/Common/DateCalculator.h index b755e2ee..3e8a78a5 100644 --- a/src/CalcViewModel/Common/DateCalculator.h +++ b/src/CalcViewModel/Common/DateCalculator.h @@ -3,11 +3,11 @@ #pragma once -const ULONGLONG c_millisecond = 10000; -const ULONGLONG c_second = 1000 * c_millisecond; -const ULONGLONG c_minute = 60 * c_second; -const ULONGLONG c_hour = 60 * c_minute; -const ULONGLONG c_day = 24 * c_hour; +const uint64_t c_millisecond = 10000; +const uint64_t c_second = 1000 * c_millisecond; +const uint64_t c_minute = 60 * c_second; +const uint64_t c_hour = 60 * c_minute; +const uint64_t c_day = 24 * c_hour; const int c_unitsOfDate = 4; // Units Year,Month,Week,Day const int c_unitsGreaterThanDays = 3; // Units Greater than Days (Year/Month/Week) 3 diff --git a/src/CalcViewModel/Common/Utils.h b/src/CalcViewModel/Common/Utils.h index 03a4c72a..a6b773af 100644 --- a/src/CalcViewModel/Common/Utils.h +++ b/src/CalcViewModel/Common/Utils.h @@ -42,10 +42,16 @@ }\ } private: t m_##n; public: -#define NAMED_OBSERVABLE_PROPERTY_RW(t, n)\ +#define OBSERVABLE_NAMED_PROPERTY_R(t, n)\ + OBSERVABLE_PROPERTY_R(t, n)\ + internal: static property Platform::String^ n##PropertyName {\ + Platform::String^ get() { return Platform::StringReference(L#n); }\ + } public: + +#define OBSERVABLE_NAMED_PROPERTY_RW(t, n)\ OBSERVABLE_PROPERTY_RW(t, n)\ - private: property Platform::StringReference n##_PropertyName {\ - Platform::StringReference get() { return Platform::StringReference(L#n); }\ + internal: static property Platform::String^ n##PropertyName {\ + Platform::String^ get() { return Platform::StringReference(L#n); }\ } public: #define OBSERVABLE_PROPERTY_FIELD(n) m_##n diff --git a/src/CalcViewModel/DataLoaders/UnitConverterDataConstants.h b/src/CalcViewModel/DataLoaders/UnitConverterDataConstants.h index bd8cb169..7032b250 100644 --- a/src/CalcViewModel/DataLoaders/UnitConverterDataConstants.h +++ b/src/CalcViewModel/DataLoaders/UnitConverterDataConstants.h @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. namespace CalculatorApp @@ -162,7 +162,8 @@ namespace CalculatorApp Data_Zebibytes = UnitStart + 162, Data_Zetabits = UnitStart + 163, Data_Zetabytes = UnitStart + 164, - UnitEnd = Data_Zetabytes + Area_Pyeong = UnitStart + 165, + UnitEnd = Area_Pyeong }; } } diff --git a/src/CalcViewModel/DataLoaders/UnitConverterDataLoader.cpp b/src/CalcViewModel/DataLoaders/UnitConverterDataLoader.cpp index 45411c1d..c95fda5a 100644 --- a/src/CalcViewModel/DataLoaders/UnitConverterDataLoader.cpp +++ b/src/CalcViewModel/DataLoaders/UnitConverterDataLoader.cpp @@ -118,12 +118,19 @@ void UnitConverterDataLoader::LoadData() unordered_map unitConversions = categoryToUnitConversionDataMap.at(categoryViewMode); double unitFactor = unitConversions[unit.id]; - for (auto itr = unitConversions.begin(); itr != unitConversions.end(); ++itr) + for (const auto&[id, conversionFactor] : unitConversions) { + if (idToUnit.find(id) == idToUnit.end()) + { + // Optional units will not be in idToUnit but can be in unitConversions. + // For optional units that did not make it to the current set of units, just continue. + continue; + } + UCM::ConversionData parsedData = { 1.0, 0.0, false }; - assert(itr->second > 0); // divide by zero assert - parsedData.ratio = unitFactor / itr->second; - conversions.insert(pair(idToUnit.at(itr->first), parsedData)); + assert(conversionFactor > 0); // divide by zero assert + parsedData.ratio = unitFactor / conversionFactor; + conversions.insert(pair(idToUnit.at(id), parsedData)); } } else @@ -175,6 +182,10 @@ void UnitConverterDataLoader::GetUnits(_In_ unordered_map areaUnits; areaUnits.push_back(OrderedUnit{ UnitConverterUnits::Area_Acre, GetLocalizedStringName(L"UnitName_Acre"), GetLocalizedStringName(L"UnitAbbreviation_Acre"), 9 }); areaUnits.push_back(OrderedUnit{ UnitConverterUnits::Area_Hectare, GetLocalizedStringName(L"UnitName_Hectare"), GetLocalizedStringName(L"UnitAbbreviation_Hectare"), 4 }); @@ -190,6 +201,10 @@ void UnitConverterDataLoader::GetUnits(_In_ unordered_map dataUnits; @@ -384,6 +399,7 @@ void UnitConverterDataLoader::GetConversionData(_In_ unordered_map()), m_MemorizedNumbers(ref new Vector()), m_IsMemoryEmpty(true), m_IsFToEChecked(false), @@ -86,8 +80,8 @@ StandardCalculatorViewModel::StandardCalculatorViewModel() : m_isBinaryBitFlippingEnabled(false), m_CurrentRadixType(RADIX_TYPE::DEC_RADIX), m_CurrentAngleType(NumbersAndOperatorsEnum::Degree), - m_OpenParenthesisCount(L""), m_Announcement(nullptr), + m_OpenParenthesisCount(0), m_feedbackForButtonPress(nullptr), m_isRtlLanguage(false), m_localizedMaxDigitsReachedAutomationFormat(nullptr), @@ -108,7 +102,6 @@ StandardCalculatorViewModel::StandardCalculatorViewModel() : m_localizedDecimalAutomationFormat = AppResourceProvider::GetInstance().GetResourceString(CalculatorResourceKeys::DecButton); m_localizedOctalAutomationFormat = AppResourceProvider::GetInstance().GetResourceString(CalculatorResourceKeys::OctButton); m_localizedBinaryAutomationFormat = AppResourceProvider::GetInstance().GetResourceString(CalculatorResourceKeys::BinButton); - m_leftParenthesisAutomationFormat = AppResourceProvider::GetInstance().GetResourceString(CalculatorResourceKeys::LeftParenthesisAutomationFormat); // Initialize the Automation Name CalculationResultAutomationName = GetLocalizedStringFormat(m_localizedCalculationResultAutomationFormat, m_DisplayValue); @@ -222,19 +215,23 @@ void StandardCalculatorViewModel::DisplayPasteError() m_standardCalculatorManager.DisplayPasteError(); } -void StandardCalculatorViewModel::SetParenthesisCount(_In_ const wstring& parenthesisCount) +void StandardCalculatorViewModel::SetParenthesisCount(_In_ unsigned int parenthesisCount) { + if (m_OpenParenthesisCount == parenthesisCount) + { + return; + } + + OpenParenthesisCount = parenthesisCount; if (IsProgrammer || IsScientific) { - OpenParenthesisCount = ref new String(parenthesisCount.c_str()); - RaisePropertyChanged("LeftParenthesisAutomationName"); + SetOpenParenthesisCountNarratorAnnouncement(); } } void StandardCalculatorViewModel::SetOpenParenthesisCountNarratorAnnouncement() { - String^ parenthesisCount = ((m_OpenParenthesisCount == nullptr) ? "0" : m_OpenParenthesisCount); - wstring localizedParenthesisCount = parenthesisCount->Data(); + wstring localizedParenthesisCount = to_wstring(m_OpenParenthesisCount).c_str(); LocalizationSettings::GetInstance().LocalizeDisplayValue(&localizedParenthesisCount); String^ announcement = LocalizationStringUtil::GetLocalizedNarratorAnnouncement( @@ -287,15 +284,6 @@ void StandardCalculatorViewModel::DisableButtons(CommandType selectedExpressionC } } -String ^ StandardCalculatorViewModel::GetLeftParenthesisAutomationName() -{ - String^ parenthesisCount = ((m_OpenParenthesisCount == nullptr) ? "0" : m_OpenParenthesisCount); - wstring localizedParenthesisCount = std::wstring(parenthesisCount->Data()); - LocalizationSettings::GetInstance().LocalizeDisplayValue(&localizedParenthesisCount); - - return GetLocalizedStringFormat(m_leftParenthesisAutomationFormat, ref new String(localizedParenthesisCount.c_str())); -} - void StandardCalculatorViewModel::SetExpressionDisplay(_Inout_ shared_ptr>> const &tokens, _Inout_ shared_ptr>> const &commands) { m_tokens = tokens; @@ -327,59 +315,67 @@ void StandardCalculatorViewModel::SetTokens(_Inout_ shared_ptr(); - } - else - { - m_ExpressionTokens->Clear(); - } - unsigned int nTokens = 0; tokens->GetSize(&nTokens); + + if (nTokens == 0) + { + m_ExpressionTokens->Clear(); + return; + } + pair currentToken; const auto& localizer = LocalizationSettings::GetInstance(); + const wstring separator = L" "; for (unsigned int i = 0; i < nTokens; ++i) { if (SUCCEEDED(tokens->GetAt(i, ¤tToken))) { Common::TokenType type; - const wstring separator = L" "; bool isEditable = (currentToken.second == -1) ? false : true; localizer.LocalizeDisplayValue(&(currentToken.first)); if (!isEditable) { - if (currentToken.first == separator) - { - type = TokenType::Separator; - } - else - { - type = TokenType::Operator; - } + type = currentToken.first == separator ? TokenType::Separator : TokenType::Operator; } - else { shared_ptr command; IFTPlatformException(m_commands->GetAt(static_cast(currentToken.second), &command)); + type = command->GetCommandType() == CommandType::OperandCommand ? TokenType::Operand : TokenType::Operator; + } - if (command->GetCommandType() == CommandType::OperandCommand) + auto currentTokenString = ref new String(currentToken.first.c_str()); + if (i < m_ExpressionTokens->Size) + { + auto existingItem = m_ExpressionTokens->GetAt(i); + if (type == existingItem->Type && existingItem->Token->Equals(currentTokenString)) { - type = TokenType::Operand; + existingItem->TokenPosition = i; + existingItem->IsTokenEditable = isEditable; + existingItem->CommandIndex = 0; } else { - type = TokenType::Operator; + auto expressionToken = ref new DisplayExpressionToken(currentTokenString, i, isEditable, type); + m_ExpressionTokens->InsertAt(i, expressionToken); } + + } + else + { + auto expressionToken = ref new DisplayExpressionToken(currentTokenString, i, isEditable, type); + m_ExpressionTokens->Append(expressionToken); } - DisplayExpressionToken^ expressionToken = ref new DisplayExpressionToken(ref new String(currentToken.first.c_str()), i, isEditable, type); - m_ExpressionTokens->Append(expressionToken); } } + + while (m_ExpressionTokens->Size != nTokens) + { + m_ExpressionTokens->RemoveAtEnd(); + } } String^ StandardCalculatorViewModel::GetCalculatorExpressionAutomationName() @@ -537,7 +533,7 @@ void StandardCalculatorViewModel::HandleUpdatedOperandData(Command cmdenum) { if (commandIndex == 0) { - delete [] temp; + delete[] temp; return; } @@ -558,7 +554,7 @@ void StandardCalculatorViewModel::HandleUpdatedOperandData(Command cmdenum) length = m_selectedExpressionLastData->Length() + 1; if (length > 50) { - delete [] temp; + delete[] temp; return; } for (; i < length; ++i) @@ -584,8 +580,7 @@ void StandardCalculatorViewModel::HandleUpdatedOperandData(Command cmdenum) bool StandardCalculatorViewModel::IsOperator(Command cmdenum) { - if ((cmdenum == Command::Command0) || (cmdenum == Command::Command1) || (cmdenum == Command::Command2) || (cmdenum == Command::Command3) || (cmdenum == Command::Command4) || (cmdenum == Command::Command5) - || (cmdenum == Command::Command6) || (cmdenum == Command::Command7) || (cmdenum == Command::Command8) || (cmdenum == Command::Command9) || (cmdenum == Command::CommandPNT) || (cmdenum == Command::CommandBACK) + if ((cmdenum >= Command::Command0 && cmdenum <= Command::Command9) || (cmdenum == Command::CommandPNT) || (cmdenum == Command::CommandBACK) || (cmdenum == Command::CommandEXP) || (cmdenum == Command::CommandFE) || (cmdenum == Command::ModeBasic) || (cmdenum == Command::ModeProgrammer) || (cmdenum == Command::ModeScientific) || (cmdenum == Command::CommandINV) || (cmdenum == Command::CommandCENTR) || (cmdenum == Command::CommandDEG) || (cmdenum == Command::CommandRAD) || (cmdenum == Command::CommandGRAD) || ((cmdenum >= Command::CommandBINEDITSTART) && (cmdenum <= Command::CommandBINEDITEND))) @@ -658,8 +653,7 @@ void StandardCalculatorViewModel::OnButtonPressed(Object^ parameter) { m_CurrentAngleType = numOpEnum; } - if ((cmdenum == Command::Command0) || (cmdenum == Command::Command1) || (cmdenum == Command::Command2) || (cmdenum == Command::Command3) || (cmdenum == Command::Command4) || (cmdenum == Command::Command5) - || (cmdenum == Command::Command6) || (cmdenum == Command::Command7) || (cmdenum == Command::Command8) || (cmdenum == Command::Command9) || (cmdenum == Command::CommandPNT) || (cmdenum == Command::CommandBACK) || (cmdenum == Command::CommandEXP)) + if ((cmdenum >= Command::Command0 && cmdenum <= Command::Command9) || (cmdenum == Command::CommandPNT) || (cmdenum == Command::CommandBACK) || (cmdenum == Command::CommandEXP)) { IsOperatorCommand = false; } @@ -1279,30 +1273,30 @@ void StandardCalculatorViewModel::Deserialize(Array^ state) void StandardCalculatorViewModel::OnPropertyChanged(String^ propertyname) { - if (propertyname == CalculatorViewModelProperties::IsScientific) + if (propertyname == IsScientificPropertyName) { if (IsScientific) { OnButtonPressed(NumbersAndOperatorsEnum::IsScientificMode); } } - else if (propertyname == CalculatorViewModelProperties::IsProgrammer) + else if (propertyname == IsProgrammerPropertyName) { if (IsProgrammer) { OnButtonPressed(NumbersAndOperatorsEnum::IsProgrammerMode); } } - else if (propertyname == CalculatorViewModelProperties::IsStandard) + else if (propertyname == IsStandardPropertyName) { if (IsStandard) { OnButtonPressed(NumbersAndOperatorsEnum::IsStandardMode); } } - else if (propertyname == CalculatorViewModelProperties::DisplayValue) + else if (propertyname == DisplayValuePropertyName) { - RaisePropertyChanged(CalculationResultAutomationName_PropertyName); + RaisePropertyChanged(CalculationResultAutomationNamePropertyName); Announcement = GetDisplayUpdatedNarratorAnnouncement(); } } diff --git a/src/CalcViewModel/StandardCalculatorViewModel.h b/src/CalcViewModel/StandardCalculatorViewModel.h index d7d3abde..f8140a75 100644 --- a/src/CalcViewModel/StandardCalculatorViewModel.h +++ b/src/CalcViewModel/StandardCalculatorViewModel.h @@ -31,13 +31,6 @@ namespace CalculatorApp #define ASCII_0 48 public delegate void HideMemoryClickedHandler(); public delegate void ProgModeRadixChangeHandler(); - namespace CalculatorViewModelProperties - { - extern Platform::StringReference IsMemoryEmpty; - extern Platform::StringReference IsInError; - extern Platform::StringReference BinaryDisplayValue; - extern Platform::StringReference OpenParenthesisCount; - } [Windows::UI::Xaml::Data::Bindable] public ref class StandardCalculatorViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged @@ -52,14 +45,14 @@ namespace CalculatorApp OBSERVABLE_OBJECT_CALLBACK(OnPropertyChanged); OBSERVABLE_PROPERTY_RW(Platform::String^, DisplayValue); OBSERVABLE_PROPERTY_RW(HistoryViewModel^, HistoryVM); - OBSERVABLE_PROPERTY_RW(bool, IsInError); + OBSERVABLE_NAMED_PROPERTY_RW(bool, IsInError); OBSERVABLE_PROPERTY_RW(bool, IsOperatorCommand); OBSERVABLE_PROPERTY_RW(Platform::String^, DisplayStringExpression); - OBSERVABLE_PROPERTY_RW(Windows::Foundation::Collections::IVector^, ExpressionTokens); + OBSERVABLE_PROPERTY_R(Windows::Foundation::Collections::IObservableVector^, ExpressionTokens); OBSERVABLE_PROPERTY_RW(Platform::String^, DecimalDisplayValue); OBSERVABLE_PROPERTY_RW(Platform::String^, HexDisplayValue); OBSERVABLE_PROPERTY_RW(Platform::String^, OctalDisplayValue); - OBSERVABLE_PROPERTY_RW(Platform::String^, BinaryDisplayValue); + OBSERVABLE_NAMED_PROPERTY_RW(Platform::String^, BinaryDisplayValue); OBSERVABLE_PROPERTY_RW(Platform::String^, HexDisplayValue_AutomationName); OBSERVABLE_PROPERTY_RW(Platform::String^, DecDisplayValue_AutomationName); OBSERVABLE_PROPERTY_RW(Platform::String^, OctDisplayValue_AutomationName); @@ -70,30 +63,29 @@ namespace CalculatorApp OBSERVABLE_PROPERTY_RW(bool, IsDecimalEnabled); OBSERVABLE_PROPERTY_RW(bool, IsCurrentViewPinned); OBSERVABLE_PROPERTY_RW(Windows::Foundation::Collections::IVector^, MemorizedNumbers); - OBSERVABLE_PROPERTY_RW(bool, IsMemoryEmpty); + OBSERVABLE_NAMED_PROPERTY_RW(bool, IsMemoryEmpty); OBSERVABLE_PROPERTY_RW(bool, IsFToEChecked); OBSERVABLE_PROPERTY_RW(bool, IsFToEEnabled); OBSERVABLE_PROPERTY_RW(bool, IsHyperbolicChecked); OBSERVABLE_PROPERTY_RW(bool, AreHEXButtonsEnabled); - NAMED_OBSERVABLE_PROPERTY_RW(Platform::String^, CalculationResultAutomationName); - NAMED_OBSERVABLE_PROPERTY_RW(Platform::String^, CalculationExpressionAutomationName); + OBSERVABLE_PROPERTY_RW(Platform::String^, CalculationResultAutomationName); + OBSERVABLE_PROPERTY_RW(Platform::String^, CalculationExpressionAutomationName); OBSERVABLE_PROPERTY_RW(bool, IsShiftProgrammerChecked); OBSERVABLE_PROPERTY_RW(bool, IsQwordEnabled); OBSERVABLE_PROPERTY_RW(bool, IsDwordEnabled); OBSERVABLE_PROPERTY_RW(bool, IsWordEnabled); OBSERVABLE_PROPERTY_RW(bool, IsByteEnabled); - OBSERVABLE_PROPERTY_RW(Platform::String^, OpenParenthesisCount); OBSERVABLE_PROPERTY_RW(int, CurrentRadixType); OBSERVABLE_PROPERTY_RW(bool, AreTokensUpdated); OBSERVABLE_PROPERTY_RW(bool, AreHistoryShortcutsEnabled); OBSERVABLE_PROPERTY_RW(bool, AreProgrammerRadixOperatorsEnabled); OBSERVABLE_PROPERTY_RW(CalculatorApp::Common::Automation::NarratorAnnouncement^, Announcement); + OBSERVABLE_PROPERTY_R(unsigned int, OpenParenthesisCount); COMMAND_FOR_METHOD(CopyCommand, StandardCalculatorViewModel::OnCopyCommand); COMMAND_FOR_METHOD(PasteCommand, StandardCalculatorViewModel::OnPasteCommand); COMMAND_FOR_METHOD(ButtonPressed, StandardCalculatorViewModel::OnButtonPressed); COMMAND_FOR_METHOD(ClearMemoryCommand, StandardCalculatorViewModel::OnClearMemoryCommand); - COMMAND_FOR_METHOD(PinUnpinAppBarButtonOnClicked, StandardCalculatorViewModel::OnPinUnpinCommand); COMMAND_FOR_METHOD(MemoryItemPressed, StandardCalculatorViewModel::OnMemoryItemPressed); COMMAND_FOR_METHOD(MemoryAdd, StandardCalculatorViewModel::OnMemoryAdd); COMMAND_FOR_METHOD(MemorySubtract, StandardCalculatorViewModel::OnMemorySubtract); @@ -262,14 +254,6 @@ namespace CalculatorApp void set(bool value) { m_completeTextSelection = value; } } - property Platform::String^ LeftParenthesisAutomationName - { - Platform::String^ get() - { - return GetLeftParenthesisAutomationName(); - } - } - internal: void OnPaste(Platform::String^ pastedString, CalculatorApp::Common::ViewMode mode); void OnCopyCommand(Platform::Object^ parameter); @@ -290,7 +274,7 @@ namespace CalculatorApp void SetTokens(_Inout_ std::shared_ptr>> const &tokens); void SetExpressionDisplay(_Inout_ std::shared_ptr>> const &tokens, _Inout_ std::shared_ptr>> const &commands); void SetHistoryExpressionDisplay(_Inout_ std::shared_ptr>> const &tokens, _Inout_ std::shared_ptr>> const &commands); - void SetParenthesisCount(_In_ const std::wstring& parenthesisCount); + void SetParenthesisCount(_In_ unsigned int parenthesisCount); void SetOpenParenthesisCountNarratorAnnouncement(); void OnNoRightParenAdded(); void SetNoParenAddedNarratorAnnouncement(); @@ -361,7 +345,6 @@ namespace CalculatorApp bool m_isLastOperationHistoryLoad; Platform::String^ m_selectedExpressionLastData; Common::DisplayExpressionToken^ m_selectedExpressionToken; - Platform::String^ m_leftParenthesisAutomationFormat; Platform::String^ LocalizeDisplayValue(_In_ std::wstring const &displayValue, _In_ bool isError); Platform::String^ CalculateNarratorDisplayValue(_In_ std::wstring const &displayValue, _In_ Platform::String^ localizedDisplayValue, _In_ bool isError); @@ -371,7 +354,6 @@ namespace CalculatorApp CalculationManager::Command ConvertToOperatorsEnum(NumbersAndOperatorsEnum operation); void DisableButtons(CalculationManager::CommandType selectedExpressionCommandType); - Platform::String^ GetLeftParenthesisAutomationName(); Platform::String^ m_feedbackForButtonPress; void OnButtonPressed(Platform::Object^ parameter); diff --git a/src/CalcViewModel/UnitConverterViewModel.cpp b/src/CalcViewModel/UnitConverterViewModel.cpp index 1cf478f0..446ae582 100644 --- a/src/CalcViewModel/UnitConverterViewModel.cpp +++ b/src/CalcViewModel/UnitConverterViewModel.cpp @@ -1,4 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. +// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #include "pch.h" @@ -56,47 +56,37 @@ constexpr unsigned int CONVERSION_FINALIZED_DELAY_IN_MS = 1000; const wregex regexTrimSpacesStart = wregex(L"^\\s+"); const wregex regexTrimSpacesEnd = wregex(L"\\s+$"); -namespace CalculatorApp::ViewModel +namespace { - namespace UnitConverterViewModelProperties - { - StringReference CurrentCategory(L"CurrentCategory"); - StringReference Unit1(L"Unit1"); - StringReference Unit2(L"Unit2"); - StringReference Value1Active(L"Value1Active"); - StringReference Value2Active(L"Value2Active"); - StringReference Value1(L"Value1"); - StringReference Value2(L"Value2"); - StringReference Value1AutomationName(L"Value1AutomationName"); - StringReference Value2AutomationName(L"Value2AutomationName"); - StringReference SupplementaryVisibility(L"SupplementaryVisibility"); - StringReference SupplementaryResults(L"SupplementaryResults"); - StringReference Unit1AutomationName(L"Unit1AutomationName"); - StringReference Unit2AutomationName(L"Unit2AutomationName"); - StringReference CurrencySymbol1(L"CurrencySymbol1"); - StringReference CurrencySymbol2(L"CurrencySymbol2"); - StringReference CurrencySymbolVisibility(L"CurrencySymbolVisibility"); - StringReference CurrencyRatioEquality(L"CurrencyRatioEquality"); - StringReference CurrencyRatioEqualityAutomationName(L"CurrencyRatioEqualityAutomationName"); - StringReference NetworkBehavior(L"NetworkBehavior"); - StringReference CurrencyDataLoadFailed(L"CurrencyDataLoadFailed"); - StringReference CurrencyDataIsWeekOld(L"CurrencyDataIsWeekOld"); - StringReference IsCurrencyLoadingVisible(L"IsCurrencyLoadingVisible"); - } + StringReference CurrentCategoryPropertyName(L"CurrentCategory"); + StringReference Unit1AutomationNamePropertyName(L"Unit1AutomationName"); + StringReference Unit2AutomationNamePropertyName(L"Unit2AutomationName"); + StringReference Unit1PropertyName(L"Unit1"); + StringReference Unit2PropertyName(L"Unit2"); + StringReference Value1PropertyName(L"Value1"); + StringReference Value2PropertyName(L"Value2"); + StringReference Value1ActivePropertyName(L"Value1Active"); + StringReference Value2ActivePropertyName(L"Value2Active"); + StringReference Value1AutomationNamePropertyName(L"Value1AutomationName"); + StringReference Value2AutomationNamePropertyName(L"Value2AutomationName"); + StringReference CurrencySymbol1PropertyName(L"CurrencySymbol1"); + StringReference CurrencySymbol2PropertyName(L"CurrencySymbol2"); + StringReference CurrencySymbolVisibilityPropertyName(L"CurrencySymbolVisibility"); + StringReference SupplementaryVisibilityPropertyName(L"SupplementaryVisibility"); +} - namespace UnitConverterResourceKeys - { - StringReference ValueFromFormat(L"Format_ValueFrom"); - StringReference ValueFromDecimalFormat(L"Format_ValueFrom_Decimal"); - StringReference ValueToFormat(L"Format_ValueTo"); - StringReference ConversionResultFormat(L"Format_ConversionResult"); - StringReference InputUnit_Name(L"InputUnit_Name"); - StringReference OutputUnit_Name(L"OutputUnit_Name"); - StringReference MaxDigitsReachedFormat(L"Format_MaxDigitsReached"); - StringReference UpdatingCurrencyRates(L"UpdatingCurrencyRates"); - StringReference CurrencyRatesUpdated(L"CurrencyRatesUpdated"); - StringReference CurrencyRatesUpdateFailed(L"CurrencyRatesUpdateFailed"); - } +namespace CalculatorApp::ViewModel::UnitConverterResourceKeys +{ + StringReference ValueFromFormat(L"Format_ValueFrom"); + StringReference ValueFromDecimalFormat(L"Format_ValueFrom_Decimal"); + StringReference ValueToFormat(L"Format_ValueTo"); + StringReference ConversionResultFormat(L"Format_ConversionResult"); + StringReference InputUnit_Name(L"InputUnit_Name"); + StringReference OutputUnit_Name(L"OutputUnit_Name"); + StringReference MaxDigitsReachedFormat(L"Format_MaxDigitsReached"); + StringReference UpdatingCurrencyRates(L"UpdatingCurrencyRates"); + StringReference CurrencyRatesUpdated(L"CurrencyRatesUpdated"); + StringReference CurrencyRatesUpdateFailed(L"CurrencyRatesUpdateFailed"); } UnitConverterViewModel::UnitConverterViewModel(const shared_ptr& model) : @@ -175,12 +165,16 @@ void UnitConverterViewModel::PopulateData() } void UnitConverterViewModel::OnCategoryChanged(Object^ parameter) +{ + m_model->SendCommand(UCM::Command::Clear); + ResetCategory(); +} + +void UnitConverterViewModel::ResetCategory() { UCM::Category currentCategory = CurrentCategory->GetModelCategory(); IsCurrencyCurrentCategory = currentCategory.id == NavCategory::Serialize(ViewMode::Currency); - m_model->SendCommand(UCM::Command::Clear); - m_isInputBlocked = false; SetSelectedUnits(); @@ -281,8 +275,8 @@ void UnitConverterViewModel::OnSwitchActive(Platform::Object^ unused) Utils::Swap(&m_localizedValueFromFormat, &m_localizedValueToFormat); Utils::Swap(&m_Unit1AutomationName, &m_Unit2AutomationName); - RaisePropertyChanged(UnitConverterViewModelProperties::Unit1AutomationName); - RaisePropertyChanged(UnitConverterViewModelProperties::Unit2AutomationName); + RaisePropertyChanged(Unit1AutomationNamePropertyName); + RaisePropertyChanged(Unit2AutomationNamePropertyName); m_isInputBlocked = false; m_model->SwitchActive(m_valueFromUnlocalized); @@ -404,7 +398,7 @@ String^ UnitConverterViewModel::ConvertToLocalizedString(const std::wstring& str void UnitConverterViewModel::DisplayPasteError() { - String^ errorMsg = AppResourceProvider::GetInstance().GetCEngineString(SIDS_DOMAIN); /*SIDS_DOMAIN is for "invalid input"*/ + String^ errorMsg = AppResourceProvider::GetInstance().GetCEngineString(StringReference(SIDS_DOMAIN)); /*SIDS_DOMAIN is for "invalid input"*/ Value1 = errorMsg; Value2 = errorMsg; m_relocalizeStringOnSwitch = false; @@ -561,13 +555,13 @@ void UnitConverterViewModel::OnPropertyChanged(Platform::String^ prop) { static bool isCategoryChanging = false; - if (prop->Equals(UnitConverterViewModelProperties::CurrentCategory)) + if (prop == CurrentCategoryPropertyName) { isCategoryChanging = true; CategoryChanged->Execute(nullptr); isCategoryChanging = false; } - else if (prop->Equals(UnitConverterViewModelProperties::Unit1) || prop->Equals(UnitConverterViewModelProperties::Unit2)) + else if (prop == Unit1PropertyName || prop == Unit2PropertyName) { // Category changes will handle updating units after they've both been updated. // This event should only be used to update units from explicit user interaction. @@ -576,7 +570,7 @@ void UnitConverterViewModel::OnPropertyChanged(Platform::String^ prop) UnitChanged->Execute(nullptr); } // Get the localized automation name for each CalculationResults field - if (prop->Equals(UnitConverterViewModelProperties::Unit1)) + if (prop == Unit1PropertyName) { UpdateValue1AutomationName(); } @@ -585,15 +579,15 @@ void UnitConverterViewModel::OnPropertyChanged(Platform::String^ prop) UpdateValue2AutomationName(); } } - else if (prop->Equals(UnitConverterViewModelProperties::Value1)) + else if (prop == Value1PropertyName) { UpdateValue1AutomationName(); } - else if (prop->Equals(UnitConverterViewModelProperties::Value2)) + else if (prop == Value2PropertyName) { UpdateValue2AutomationName(); } - else if (prop->Equals(UnitConverterViewModelProperties::Value1Active) || prop->Equals(UnitConverterViewModelProperties::Value2Active)) + else if (prop == Value1ActivePropertyName || prop == Value2ActivePropertyName) { // if one of the values is activated, and as a result both are true, it means // that we're trying to switch. @@ -605,11 +599,11 @@ void UnitConverterViewModel::OnPropertyChanged(Platform::String^ prop) UpdateValue1AutomationName(); UpdateValue2AutomationName(); } - else if (prop->Equals(UnitConverterViewModelProperties::SupplementaryResults)) + else if (prop == SupplementaryResultsPropertyName) { - RaisePropertyChanged(UnitConverterViewModelProperties::SupplementaryVisibility); + RaisePropertyChanged(SupplementaryVisibilityPropertyName); } - else if (prop->Equals(UnitConverterViewModelProperties::Value1AutomationName)) + else if (prop == Value1AutomationNamePropertyName) { m_isValue1Updating = false; if (!m_isValue2Updating) @@ -617,7 +611,7 @@ void UnitConverterViewModel::OnPropertyChanged(Platform::String^ prop) AnnounceConversionResult(); } } - else if (prop->Equals(UnitConverterViewModelProperties::Value2AutomationName)) + else if (prop == Value2AutomationNamePropertyName) { m_isValue2Updating = false; if (!m_isValue1Updating) @@ -625,9 +619,9 @@ void UnitConverterViewModel::OnPropertyChanged(Platform::String^ prop) AnnounceConversionResult(); } } - else if (prop->Equals(UnitConverterViewModelProperties::CurrencySymbol1) || prop->Equals(UnitConverterViewModelProperties::CurrencySymbol2)) + else if (prop == CurrencySymbol1PropertyName || prop == CurrencySymbol2PropertyName) { - RaisePropertyChanged(UnitConverterViewModelProperties::CurrencySymbolVisibility); + RaisePropertyChanged(CurrencySymbolVisibilityPropertyName); } } @@ -716,7 +710,9 @@ void UnitConverterViewModel::OnCurrencyDataLoadFinished(bool didLoad) { m_isCurrencyDataLoaded = true; CurrencyDataLoadFailed = !didLoad; - ResetView(); + m_model->ResetCategoriesAndRatios(); + m_model->Calculate(); + ResetCategory(); StringReference key = didLoad ? UnitConverterResourceKeys::CurrencyRatesUpdated : UnitConverterResourceKeys::CurrencyRatesUpdateFailed; String^ announcement = AppResourceProvider::GetInstance().GetResourceString(key); @@ -852,7 +848,7 @@ void UnitConverterViewModel::RefreshSupplementaryResults() } m_cacheMutex.unlock(); - RaisePropertyChanged(UnitConverterViewModelProperties::SupplementaryResults); + RaisePropertyChanged(SupplementaryResultsPropertyName); //EventWriteConverterSupplementaryResultsUpdated(); } diff --git a/src/CalcViewModel/UnitConverterViewModel.h b/src/CalcViewModel/UnitConverterViewModel.h index bd7b8bd5..2c6c8af3 100644 --- a/src/CalcViewModel/UnitConverterViewModel.h +++ b/src/CalcViewModel/UnitConverterViewModel.h @@ -138,25 +138,6 @@ namespace CalculatorApp return ref new Activatable(activatable); } - namespace UnitConverterViewModelProperties - { - extern Platform::StringReference CurrentCategory; - extern Platform::StringReference Unit1; - extern Platform::StringReference Unit2; - extern Platform::StringReference Value1Active; - extern Platform::StringReference Value2Active; - extern Platform::StringReference SupplementaryVisibility; - extern Platform::StringReference SupplementaryResults; - extern Platform::StringReference CurrencySymbol1; - extern Platform::StringReference CurrencySymbol2; - extern Platform::StringReference CurrencySymbolVisibility; - extern Platform::StringReference CurrencyRatioEquality; - extern Platform::StringReference NetworkBehavior; - extern Platform::StringReference CurrencyDataLoadFailed; - extern Platform::StringReference CurrencyDataIsWeekOld; - extern Platform::StringReference IsCurrencyLoadingVisible; - } - [Windows::UI::Xaml::Data::Bindable] public ref class UnitConverterViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged { @@ -176,7 +157,7 @@ namespace CalculatorApp OBSERVABLE_PROPERTY_RW(Platform::String^, CurrencySymbol2); OBSERVABLE_PROPERTY_RW(Unit^, Unit2); OBSERVABLE_PROPERTY_RW(Platform::String^, Value2); - OBSERVABLE_PROPERTY_R(Windows::Foundation::Collections::IObservableVector^, SupplementaryResults); + OBSERVABLE_NAMED_PROPERTY_R(Windows::Foundation::Collections::IObservableVector^, SupplementaryResults); OBSERVABLE_PROPERTY_RW(bool, Value1Active); OBSERVABLE_PROPERTY_RW(bool, Value2Active); OBSERVABLE_PROPERTY_RW(Platform::String^, Value1AutomationName); @@ -187,14 +168,14 @@ namespace CalculatorApp OBSERVABLE_PROPERTY_RW(bool, IsDecimalEnabled); OBSERVABLE_PROPERTY_RW(bool, IsDropDownOpen); OBSERVABLE_PROPERTY_RW(bool, IsDropDownEnabled); - OBSERVABLE_PROPERTY_RW(bool, IsCurrencyLoadingVisible); + OBSERVABLE_NAMED_PROPERTY_RW(bool, IsCurrencyLoadingVisible); OBSERVABLE_PROPERTY_RW(bool, IsCurrencyCurrentCategory); OBSERVABLE_PROPERTY_RW(Platform::String^, CurrencyRatioEquality); OBSERVABLE_PROPERTY_RW(Platform::String^, CurrencyRatioEqualityAutomationName); OBSERVABLE_PROPERTY_RW(Platform::String^, CurrencyTimestamp); - OBSERVABLE_PROPERTY_RW(CalculatorApp::NetworkAccessBehavior, NetworkBehavior); - OBSERVABLE_PROPERTY_RW(bool, CurrencyDataLoadFailed); - OBSERVABLE_PROPERTY_RW(bool, CurrencyDataIsWeekOld); + OBSERVABLE_NAMED_PROPERTY_RW(CalculatorApp::NetworkAccessBehavior, NetworkBehavior); + OBSERVABLE_NAMED_PROPERTY_RW(bool, CurrencyDataLoadFailed); + OBSERVABLE_NAMED_PROPERTY_RW(bool, CurrencyDataIsWeekOld); property Windows::UI::Xaml::Visibility SupplementaryVisibility { @@ -242,6 +223,7 @@ namespace CalculatorApp void UpdateValue2AutomationName(); Platform::String^ Serialize(); void Deserialize(Platform::String^ state); + void ResetCategoriesAndRatio(); // Saving And Restoring User Preferences of Category and Associated-Units across Sessions. void SaveUserPreferences(); @@ -282,6 +264,7 @@ namespace CalculatorApp void RefreshSupplementaryResults(); void UpdateInputBlocked(_In_ const std::wstring& currencyInput); bool UnitsAreValid(); + void ResetCategory(); void OnButtonPressed(Platform::Object^ parameter); Platform::String^ ConvertToLocalizedString(const std::wstring& stringToLocalize, bool allowPartialStrings); diff --git a/src/CalcViewModel/pch.h b/src/CalcViewModel/pch.h index 1d03c5e5..17128bc6 100644 --- a/src/CalcViewModel/pch.h +++ b/src/CalcViewModel/pch.h @@ -10,6 +10,10 @@ #define WIN32_LEAN_AND_MEAN #endif +// Windows headers define min/max macros. +// Disable it for project code. +#define NOMINMAX + #include #include diff --git a/src/Calculator/AboutFlyout.xaml b/src/Calculator/AboutFlyout.xaml index cfce6fbc..c2d82f47 100644 --- a/src/Calculator/AboutFlyout.xaml +++ b/src/Calculator/AboutFlyout.xaml @@ -38,7 +38,7 @@ - + SetVersionString(); Header->Text = resourceLoader.GetResourceString("AboutButton/Content"); + + auto copyrightText = LocalizationStringUtil::GetLocalizedString(resourceLoader.GetResourceString("AboutControlCopyright")->Data(), to_wstring(BUILD_YEAR).c_str()); + AboutControlCopyrightRun->Text = ref new String(copyrightText.c_str()); + } void AboutFlyout::FeedbackButton_Click(_In_ Object^ sender, _In_ RoutedEventArgs^ e) diff --git a/src/Calculator/App.xaml b/src/Calculator/App.xaml index 60103662..918034c0 100644 --- a/src/Calculator/App.xaml +++ b/src/Calculator/App.xaml @@ -19,7 +19,6 @@ #FF2B2B2B - @@ -34,7 +33,11 @@ FallbackColor="Transparent" TargetTheme="Dark" Color="Transparent"/> - + @@ -51,7 +54,6 @@ #FFE0E0E0 - @@ -66,7 +68,11 @@ FallbackColor="Transparent" TargetTheme="Light" Color="Transparent"/> - + @@ -81,7 +87,6 @@ 2 - @@ -93,7 +98,8 @@ - + + @@ -125,10 +131,6 @@ 15 - 72 - 46 - 28 - @@ -351,7 +353,8 @@ - - - - - - + - - - - - - - - - - - - - - - - + - -