diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 00000000..ef903269 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.13) +project(calculator CXX) +set(CMAKE_CXX_STANDARD 17) + +if(CMAKE_CXX_COMPILER MATCHES ".*clang") + # Clang disagress with libstdc++ about constexpr-ness of wstring_view + # See https://github.com/Microsoft/calculator/pull/321 + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") +endif() + +add_subdirectory(CalcManager) diff --git a/src/CalcManager/CEngine/CMakeLists.txt b/src/CalcManager/CEngine/CMakeLists.txt new file mode 100644 index 00000000..ba4348ff --- /dev/null +++ b/src/CalcManager/CEngine/CMakeLists.txt @@ -0,0 +1,14 @@ +target_sources(CalcManager PRIVATE + calc.cpp + CalcInput.cpp + CalcUtils.cpp + History.cpp + Number.cpp + Rational.cpp + RationalMath.cpp + scicomm.cpp + scidisp.cpp + scifunc.cpp + scioper.cpp + sciset.cpp +) diff --git a/src/CalcManager/CEngine/Rational.cpp b/src/CalcManager/CEngine/Rational.cpp index a0bcd97d..8eb4a91a 100644 --- a/src/CalcManager/CEngine/Rational.cpp +++ b/src/CalcManager/CEngine/Rational.cpp @@ -1,6 +1,5 @@ // Copyright (c) Microsoft Corporation. All rights reserved. -#include #include "Header Files/Rational.h" using namespace std; @@ -53,8 +52,8 @@ namespace CalcEngine Rational::Rational(uint64_t ui) { - uint32_t hi = HIDWORD(ui); - uint32_t lo = LODWORD(ui); + uint32_t hi = (uint32_t) (((ui) >> 32) & 0xffffffff); + uint32_t lo = (uint32_t) ui; Rational temp = (Rational{ hi } << 32) | lo; diff --git a/src/CalcManager/CMakeLists.txt b/src/CalcManager/CMakeLists.txt new file mode 100644 index 00000000..c02bc78d --- /dev/null +++ b/src/CalcManager/CMakeLists.txt @@ -0,0 +1,11 @@ +add_library(CalcManager + CalculatorHistory.cpp + CalculatorManager.cpp + ExpressionCommand.cpp + pch.cpp + UnitConverter.cpp +) +target_include_directories(CalcManager PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + +add_subdirectory(Ratpack) +add_subdirectory(CEngine) diff --git a/src/CalcManager/CalculatorManager.cpp b/src/CalcManager/CalculatorManager.cpp index d054f5b1..e09d7d90 100644 --- a/src/CalcManager/CalculatorManager.cpp +++ b/src/CalcManager/CalculatorManager.cpp @@ -12,6 +12,10 @@ using namespace CalcEngine; static constexpr size_t MAX_HISTORY_ITEMS = 20; static constexpr size_t SERIALIZED_NUMBER_MINSIZE = 3; +#ifndef _MSC_VER +#define __pragma(x) +#endif + // Converts Memory Command enum value to unsigned char, // while ignoring Warning C4309: 'conversion' : truncation of constant value #define MEMORY_COMMAND_TO_UNSIGNED_CHAR(c) __pragma(warning(push)) __pragma(warning(disable : 4309)) static_cast(c) __pragma(warning(pop)) diff --git a/src/CalcManager/CalculatorVector.h b/src/CalcManager/CalculatorVector.h index e89b55e4..bd82abbc 100644 --- a/src/CalcManager/CalculatorVector.h +++ b/src/CalcManager/CalculatorVector.h @@ -5,10 +5,10 @@ #include #include -#include +#include "winerror_cross_platform.h" #include "Ratpack/CalcErr.h" #include // for std::out_of_range -#include // for SAL +#include "sal_cross_platform.h" // for SAL template class CalculatorVector diff --git a/src/CalcManager/Header Files/EngineStrings.h b/src/CalcManager/Header Files/EngineStrings.h index a85fc508..fffebf0d 100644 --- a/src/CalcManager/Header Files/EngineStrings.h +++ b/src/CalcManager/Header Files/EngineStrings.h @@ -16,7 +16,10 @@ #pragma once +#include #include +#include +#include inline constexpr auto IDS_ERRORS_FIRST = 99; diff --git a/src/CalcManager/Ratpack/CMakeLists.txt b/src/CalcManager/Ratpack/CMakeLists.txt new file mode 100644 index 00000000..3fbd7ae3 --- /dev/null +++ b/src/CalcManager/Ratpack/CMakeLists.txt @@ -0,0 +1,14 @@ +target_sources(CalcManager PRIVATE + basex.cpp + conv.cpp + exp.cpp + fact.cpp + itrans.cpp + itransh.cpp + logic.cpp + num.cpp + rat.cpp + support.cpp + trans.cpp + transh.cpp +) diff --git a/src/CalcManager/Ratpack/conv.cpp b/src/CalcManager/Ratpack/conv.cpp index 9a944ea5..d96fe306 100644 --- a/src/CalcManager/Ratpack/conv.cpp +++ b/src/CalcManager/Ratpack/conv.cpp @@ -18,7 +18,7 @@ //--------------------------------------------------------------------------- #include -#include +#include "winerror_cross_platform.h" #include #include // for memmove, memcpy #include "ratpak.h" diff --git a/src/CalcManager/Ratpack/ratpak.h b/src/CalcManager/Ratpack/ratpak.h index 2e7c973c..dc6a98d9 100644 --- a/src/CalcManager/Ratpack/ratpak.h +++ b/src/CalcManager/Ratpack/ratpak.h @@ -21,7 +21,7 @@ #include #include "CalcErr.h" #include // for memmove -#include // for SAL +#include "sal_cross_platform.h" // 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 diff --git a/src/CalcManager/UnitConverter.cpp b/src/CalcManager/UnitConverter.cpp index 57cd49bd..bbf761ba 100644 --- a/src/CalcManager/UnitConverter.cpp +++ b/src/CalcManager/UnitConverter.cpp @@ -2,12 +2,12 @@ // Licensed under the MIT License. #include +#include #include #include // for std::sort #include "Command.h" #include "UnitConverter.h" -using namespace concurrency; using namespace std; using namespace UnitConversionManager; @@ -229,7 +229,7 @@ Unit UnitConverter::StringToUnit(const wstring& w) vector tokenList = StringToVector(w, L";"); assert(tokenList.size() == EXPECTEDSERIALIZEDUNITTOKENCOUNT); Unit serializedUnit; - serializedUnit.id = _wtoi(Unquote(tokenList[0]).c_str()); + serializedUnit.id = wcstol(Unquote(tokenList[0]).c_str(), nullptr, 10); serializedUnit.name = Unquote(tokenList[1]); serializedUnit.accessibleName = serializedUnit.name; serializedUnit.abbreviation = Unquote(tokenList[2]); @@ -244,7 +244,7 @@ Category UnitConverter::StringToCategory(const wstring& w) vector tokenList = StringToVector(w, L";"); assert(tokenList.size() == EXPECTEDSERIALIZEDCATEGORYTOKENCOUNT); Category serializedCategory; - serializedCategory.id = _wtoi(Unquote(tokenList[0]).c_str()); + serializedCategory.id = wcstol(Unquote(tokenList[0]).c_str(), nullptr, 10); serializedCategory.supportsNegative = (tokenList[1].compare(L"1") == 0); serializedCategory.name = Unquote(tokenList[2]); return serializedCategory; @@ -536,30 +536,31 @@ void UnitConverter::SetViewModelCurrencyCallback(_In_ const shared_ptr> UnitConverter::RefreshCurrencyRatios() +future> UnitConverter::RefreshCurrencyRatios() { shared_ptr currencyDataLoader = GetCurrencyConverterDataLoader(); - return create_task([this, currencyDataLoader]() { - if (currencyDataLoader != nullptr) - { - return currencyDataLoader->TryLoadDataFromWebOverrideAsync(); - } - else - { - return task_from_result(false); - } - }) - .then( - [this, currencyDataLoader](bool didLoad) { - wstring timestamp = L""; - if (currencyDataLoader != nullptr) - { - timestamp = currencyDataLoader->GetCurrencyTimestamp(); - } + future loadDataResult; + if (currencyDataLoader != nullptr) + { + loadDataResult = currencyDataLoader->TryLoadDataFromWebOverrideAsync(); + } + else + { + loadDataResult = async([] { return false; }); + } - return make_pair(didLoad, timestamp); - }, - task_continuation_context::use_default()); + shared_future sharedLoadResult = loadDataResult.share(); + return async([this, currencyDataLoader, sharedLoadResult]() { + sharedLoadResult.wait(); + bool didLoad = sharedLoadResult.get(); + wstring timestamp = L""; + if (currencyDataLoader != nullptr) + { + timestamp = currencyDataLoader->GetCurrencyTimestamp(); + } + + return make_pair(didLoad, timestamp); + }); } shared_ptr UnitConverter::GetCurrencyConverterDataLoader() diff --git a/src/CalcManager/UnitConverter.h b/src/CalcManager/UnitConverter.h index 19582245..0d1b8acd 100644 --- a/src/CalcManager/UnitConverter.h +++ b/src/CalcManager/UnitConverter.h @@ -5,8 +5,8 @@ #include #include -#include -#include // for SAL +#include +#include "sal_cross_platform.h" // for SAL #include // for std::shared_ptr namespace UnitConversionManager @@ -211,9 +211,9 @@ namespace UnitConversionManager GetCurrencyRatioEquality(_In_ const UnitConversionManager::Unit& unit1, _In_ const UnitConversionManager::Unit& unit2) = 0; virtual std::wstring GetCurrencyTimestamp() = 0; - virtual concurrency::task TryLoadDataFromCacheAsync() = 0; - virtual concurrency::task TryLoadDataFromWebAsync() = 0; - virtual concurrency::task TryLoadDataFromWebOverrideAsync() = 0; + virtual std::future TryLoadDataFromCacheAsync() = 0; + virtual std::future TryLoadDataFromWebAsync() = 0; + virtual std::future TryLoadDataFromWebOverrideAsync() = 0; }; class IUnitConverterVMCallback @@ -242,7 +242,7 @@ namespace UnitConversionManager virtual void SendCommand(Command command) = 0; 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 std::future> RefreshCurrencyRatios() = 0; virtual void Calculate() = 0; virtual void ResetCategoriesAndRatios() = 0; }; @@ -265,7 +265,7 @@ namespace UnitConversionManager void SendCommand(Command command) override; void SetViewModelCallback(_In_ const std::shared_ptr& newCallback) override; void SetViewModelCurrencyCallback(_In_ const std::shared_ptr& newCallback) override; - concurrency::task> RefreshCurrencyRatios() override; + std::future> RefreshCurrencyRatios() override; void Calculate() override; void ResetCategoriesAndRatios() override; // IUnitConverter diff --git a/src/CalcManager/pch.h b/src/CalcManager/pch.h index e66e1a38..2bcedb7a 100644 --- a/src/CalcManager/pch.h +++ b/src/CalcManager/pch.h @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/CalcManager/sal_cross_platform.h b/src/CalcManager/sal_cross_platform.h new file mode 100644 index 00000000..416bf096 --- /dev/null +++ b/src/CalcManager/sal_cross_platform.h @@ -0,0 +1,19 @@ +#pragma once + +#if defined(_WIN32) && defined(_MSC_VER) + +#include + +#else + +// Empty macro definitions for source annotations + +#define _In_opt_ +#define _Out_opt_ +#define _In_ +#define _Out_ +#define _Inout_ +#define __in_opt +#define _Frees_ptr_opt_ + +#endif diff --git a/src/CalcManager/winerror_cross_platform.h b/src/CalcManager/winerror_cross_platform.h new file mode 100644 index 00000000..07b6cd3f --- /dev/null +++ b/src/CalcManager/winerror_cross_platform.h @@ -0,0 +1,25 @@ +#pragma once + +#if defined(_WIN32) && defined(_MSC_VER) + +#include + +#else + +#include "Ratpack/CalcErr.h" + +#define E_ACCESSDENIED 0x80070005 +#define E_FAIL 0x80004005 +#define E_INVALIDARG 0x80070057 +#define E_OUTOFMEMORY 0x8007000E +#define E_POINTER 0x80004003 +#define E_UNEXPECTED 0x8000FFFF +#define E_BOUNDS 0x8000000B +#define S_OK 0x0 +#define S_FALSE 0x1 + +#define SUCCEEDED(hr) (((ResultCode)(hr)) >= 0) +#define FAILED(hr) (((ResultCode)(hr)) < 0) +#define SCODE_CODE(sc) ((sc) & 0xFFFF) + +#endif diff --git a/src/CalcViewModel/DataLoaders/CurrencyDataLoader.cpp b/src/CalcViewModel/DataLoaders/CurrencyDataLoader.cpp index d51a1940..2e7cc3cc 100644 --- a/src/CalcViewModel/DataLoaders/CurrencyDataLoader.cpp +++ b/src/CalcViewModel/DataLoaders/CurrencyDataLoader.cpp @@ -191,7 +191,7 @@ void CurrencyDataLoader::LoadData() if (!LoadFinished()) { create_task([this]() -> task { - vector()>> loadFunctions = { + vector()>> loadFunctions = { [this]() { return TryLoadDataFromCacheAsync(); }, [this]() { return TryLoadDataFromWebAsync(); }, }; @@ -307,7 +307,7 @@ pair CurrencyDataLoader::GetCurrencyRatioEquality(_In_ const U } #pragma optimize("", off) // Turn off optimizations to work around DevDiv 393321 -task CurrencyDataLoader::TryLoadDataFromCacheAsync() +future CurrencyDataLoader::TryLoadDataFromCacheAsync() { try { @@ -349,7 +349,7 @@ task CurrencyDataLoader::TryLoadDataFromCacheAsync() } } -task CurrencyDataLoader::TryFinishLoadFromCacheAsync() +future CurrencyDataLoader::TryFinishLoadFromCacheAsync() { auto localSettings = ApplicationData::Current->LocalSettings; if (localSettings == nullptr) @@ -386,7 +386,7 @@ task CurrencyDataLoader::TryFinishLoadFromCacheAsync() co_return true; } -task CurrencyDataLoader::TryLoadDataFromWebAsync() +future CurrencyDataLoader::TryLoadDataFromWebAsync() { try { @@ -459,7 +459,7 @@ task CurrencyDataLoader::TryLoadDataFromWebAsync() } } -task CurrencyDataLoader::TryLoadDataFromWebOverrideAsync() +future CurrencyDataLoader::TryLoadDataFromWebOverrideAsync() { m_meteredOverrideSet = true; bool didLoad = co_await TryLoadDataFromWebAsync(); diff --git a/src/CalcViewModel/DataLoaders/CurrencyDataLoader.h b/src/CalcViewModel/DataLoaders/CurrencyDataLoader.h index 1ec031d1..a4be2d0e 100644 --- a/src/CalcViewModel/DataLoaders/CurrencyDataLoader.h +++ b/src/CalcViewModel/DataLoaders/CurrencyDataLoader.h @@ -76,9 +76,9 @@ namespace CalculatorApp GetCurrencyRatioEquality(_In_ const UnitConversionManager::Unit& unit1, _In_ const UnitConversionManager::Unit& unit2) override; std::wstring GetCurrencyTimestamp() override; - concurrency::task TryLoadDataFromCacheAsync() override; - concurrency::task TryLoadDataFromWebAsync() override; - concurrency::task TryLoadDataFromWebOverrideAsync() override; + std::future TryLoadDataFromCacheAsync() override; + std::future TryLoadDataFromWebAsync() override; + std::future TryLoadDataFromWebOverrideAsync() override; // ICurrencyConverterDataLoader void OnNetworkBehaviorChanged(CalculatorApp::NetworkAccessBehavior newBehavior); @@ -87,7 +87,7 @@ namespace CalculatorApp void ResetLoadStatus(); void NotifyDataLoadFinished(bool didLoad); - concurrency::task TryFinishLoadFromCacheAsync(); + std::future TryFinishLoadFromCacheAsync(); bool TryParseWebResponses( _In_ Platform::String ^ staticDataJson, diff --git a/src/CalcViewModel/UnitConverterViewModel.cpp b/src/CalcViewModel/UnitConverterViewModel.cpp index 72d31464..821cdc70 100644 --- a/src/CalcViewModel/UnitConverterViewModel.cpp +++ b/src/CalcViewModel/UnitConverterViewModel.cpp @@ -675,7 +675,7 @@ void UnitConverterViewModel::RefreshCurrencyRatios() String ^ announcement = AppResourceProvider::GetInstance().GetResourceString(UnitConverterResourceKeys::UpdatingCurrencyRates); Announcement = CalculatorAnnouncement::GetUpdateCurrencyRatesAnnouncement(announcement); - auto refreshTask = create_task(m_model->RefreshCurrencyRatios()); + auto refreshTask = create_task([this] { return m_model->RefreshCurrencyRatios().get(); }); refreshTask.then( [this](const pair& refreshResult) { bool didLoad = refreshResult.first; diff --git a/src/CalculatorUnitTests/UnitConverterViewModelUnitTests.h b/src/CalculatorUnitTests/UnitConverterViewModelUnitTests.h index 08c0f954..8601ca76 100644 --- a/src/CalculatorUnitTests/UnitConverterViewModelUnitTests.h +++ b/src/CalculatorUnitTests/UnitConverterViewModelUnitTests.h @@ -47,7 +47,7 @@ namespace CalculatorUnitTests void ResetCategoriesAndRatios() override { } - concurrency::task> RefreshCurrencyRatios() override + std::future> RefreshCurrencyRatios() override { co_return std::make_pair(true, L""); }