Cleaning up some UnitConverter code and making some of it more efficient. (#875)

This commit is contained in:
Scott Freeman 2019-12-18 04:19:28 -05:00 committed by Rudy Huyn
commit 3c6b5a808e
5 changed files with 107 additions and 108 deletions

View file

@ -109,11 +109,10 @@ CategorySelectionInitializer UnitConverter::SetCurrentCategory(const Category& i
{ {
if (m_currentCategory.id != input.id) if (m_currentCategory.id != input.id)
{ {
vector<Unit>& unitVector = m_categoryToUnits[m_currentCategory]; for (auto& unit : m_categoryToUnits[m_currentCategory])
for (unsigned int i = 0; i < unitVector.size(); i++)
{ {
unitVector[i].isConversionSource = (unitVector[i].id == m_fromType.id); unit.isConversionSource = (unit.id == m_fromType.id);
unitVector[i].isConversionTarget = (unitVector[i].id == m_toType.id); unit.isConversionTarget = (unit.id == m_toType.id);
} }
m_currentCategory = input; m_currentCategory = input;
if (!m_currentCategory.supportsNegative && m_currentDisplay.front() == L'-') if (!m_currentCategory.supportsNegative && m_currentDisplay.front() == L'-')
@ -192,41 +191,51 @@ void UnitConverter::SwitchActive(const wstring& newValue)
} }
} }
wstring UnitConverter::CategoryToString(const Category& c, const wchar_t* delimiter) wstring UnitConverter::CategoryToString(const Category& c, wstring_view delimiter)
{ {
wstringstream out(wstringstream::out); return Quote(std::to_wstring(c.id))
out << Quote(std::to_wstring(c.id)) << delimiter << Quote(std::to_wstring(c.supportsNegative)) << delimiter << Quote(c.name) << delimiter; .append(delimiter)
return out.str(); .append(Quote(std::to_wstring(c.supportsNegative)))
.append(delimiter)
.append(Quote(c.name))
.append(delimiter);
} }
vector<wstring> UnitConverter::StringToVector(const wstring& w, const wchar_t* delimiter, bool addRemainder) vector<wstring> UnitConverter::StringToVector(wstring_view w, wstring_view delimiter, bool addRemainder)
{ {
size_t delimiterIndex = w.find(delimiter); size_t delimiterIndex = w.find(delimiter);
size_t startIndex = 0; size_t startIndex = 0;
vector<wstring> serializedTokens = vector<wstring>(); vector<wstring> serializedTokens;
while (delimiterIndex != wstring::npos) while (delimiterIndex != wstring_view::npos)
{ {
serializedTokens.push_back(w.substr(startIndex, delimiterIndex - startIndex)); serializedTokens.emplace_back(w.substr(startIndex, delimiterIndex - startIndex));
startIndex = delimiterIndex + (int)wcslen(delimiter); startIndex = delimiterIndex + (int)delimiter.size();
delimiterIndex = w.find(delimiter, startIndex); delimiterIndex = w.find(delimiter, startIndex);
} }
if (addRemainder) if (addRemainder)
{ {
delimiterIndex = w.size(); delimiterIndex = w.size();
serializedTokens.push_back(w.substr(startIndex, delimiterIndex - startIndex)); serializedTokens.emplace_back(w.substr(startIndex, delimiterIndex - startIndex));
} }
return serializedTokens; return serializedTokens;
} }
wstring UnitConverter::UnitToString(const Unit& u, const wchar_t* delimiter) wstring UnitConverter::UnitToString(const Unit& u, wstring_view delimiter)
{ {
wstringstream out(wstringstream::out); return Quote(std::to_wstring(u.id))
out << Quote(std::to_wstring(u.id)) << delimiter << Quote(u.name) << delimiter << Quote(u.abbreviation) << delimiter .append(delimiter)
<< std::to_wstring(u.isConversionSource) << delimiter << std::to_wstring(u.isConversionTarget) << delimiter << std::to_wstring(u.isWhimsical) .append(Quote(u.name))
<< delimiter; .append(delimiter)
return out.str(); .append(Quote(u.abbreviation))
.append(delimiter)
.append(std::to_wstring(u.isConversionSource))
.append(delimiter)
.append(std::to_wstring(u.isConversionTarget))
.append(delimiter)
.append(std::to_wstring(u.isWhimsical))
.append(delimiter);
} }
Unit UnitConverter::StringToUnit(const wstring& w) Unit UnitConverter::StringToUnit(wstring_view w)
{ {
vector<wstring> tokenList = StringToVector(w, L";"); vector<wstring> tokenList = StringToVector(w, L";");
assert(tokenList.size() == EXPECTEDSERIALIZEDUNITTOKENCOUNT); assert(tokenList.size() == EXPECTEDSERIALIZEDUNITTOKENCOUNT);
@ -241,7 +250,7 @@ Unit UnitConverter::StringToUnit(const wstring& w)
return serializedUnit; return serializedUnit;
} }
Category UnitConverter::StringToCategory(const wstring& w) Category UnitConverter::StringToCategory(wstring_view w)
{ {
vector<wstring> tokenList = StringToVector(w, L";"); vector<wstring> tokenList = StringToVector(w, L";");
assert(tokenList.size() == EXPECTEDSERIALIZEDCATEGORYTOKENCOUNT); assert(tokenList.size() == EXPECTEDSERIALIZEDCATEGORYTOKENCOUNT);
@ -255,8 +264,8 @@ Category UnitConverter::StringToCategory(const wstring& w)
/// <summary> /// <summary>
/// De-Serializes the data in the converter from a string /// De-Serializes the data in the converter from a string
/// </summary> /// </summary>
/// <param name="userPreferences">wstring holding the serialized data. If it does not have expected number of parameters, we will ignore it</param> /// <param name="userPreferences">wstring_view holding the serialized data. If it does not have expected number of parameters, we will ignore it</param>
void UnitConverter::RestoreUserPreferences(const wstring& userPreferences) void UnitConverter::RestoreUserPreferences(wstring_view userPreferences)
{ {
if (userPreferences.empty()) if (userPreferences.empty())
{ {
@ -294,58 +303,57 @@ void UnitConverter::RestoreUserPreferences(const wstring& userPreferences)
/// </summary> /// </summary>
wstring UnitConverter::SaveUserPreferences() wstring UnitConverter::SaveUserPreferences()
{ {
wstringstream out(wstringstream::out); constexpr auto delimiter = L";"sv;
const wchar_t* delimiter = L";"; constexpr auto pipe = L"|"sv;
return UnitToString(m_fromType, delimiter)
out << UnitToString(m_fromType, delimiter) << "|"; .append(pipe)
out << UnitToString(m_toType, delimiter) << "|"; .append(UnitToString(m_toType, delimiter))
out << CategoryToString(m_currentCategory, delimiter) << "|"; .append(pipe)
wstring test = out.str(); .append(CategoryToString(m_currentCategory, delimiter))
return test; .append(pipe);
} }
/// <summary> /// <summary>
/// Sanitizes the input string, escape quoting any symbols we rely on for our delimiters, and returns the sanitized string. /// Sanitizes the input string, escape quoting any symbols we rely on for our delimiters, and returns the sanitized string.
/// </summary> /// </summary>
/// <param name="s">wstring to be sanitized</param> /// <param name="s">wstring_view to be sanitized</param>
wstring UnitConverter::Quote(const wstring& s) wstring UnitConverter::Quote(wstring_view s)
{ {
wstringstream quotedString(wstringstream::out); wstring quotedString;
// Iterate over the delimiter characters we need to quote // Iterate over the delimiter characters we need to quote
wstring::const_iterator cursor = s.begin(); for (const auto ch : s)
while (cursor != s.end())
{ {
if (quoteConversions.find(*cursor) != quoteConversions.end()) if (quoteConversions.find(ch) != quoteConversions.end())
{ {
quotedString << quoteConversions[*cursor]; quotedString += quoteConversions[ch];
} }
else else
{ {
quotedString << *cursor; quotedString += ch;
} }
++cursor;
} }
return quotedString.str();
return quotedString;
} }
/// <summary> /// <summary>
/// Unsanitizes the sanitized input string, returning it to its original contents before we had quoted it. /// Unsanitizes the sanitized input string, returning it to its original contents before we had quoted it.
/// </summary> /// </summary>
/// <param name="s">wstring to be unsanitized</param> /// <param name="s">wstring_view to be unsanitized</param>
wstring UnitConverter::Unquote(const wstring& s) wstring UnitConverter::Unquote(wstring_view s)
{ {
wstringstream quotedSubString(wstringstream::out); wstring quotedSubString;
wstringstream unquotedString(wstringstream::out); wstring unquotedString;
wstring::const_iterator cursor = s.begin(); wstring_view::const_iterator cursor = s.begin();
while (cursor != s.end()) while (cursor != s.end())
{ {
if (*cursor == LEFTESCAPECHAR) if (*cursor == LEFTESCAPECHAR)
{ {
quotedSubString.str(L""); quotedSubString.clear();
while (cursor != s.end() && *cursor != RIGHTESCAPECHAR) while (cursor != s.end() && *cursor != RIGHTESCAPECHAR)
{ {
quotedSubString << *cursor; quotedSubString += *cursor;
++cursor; ++cursor;
} }
if (cursor == s.end()) if (cursor == s.end())
@ -355,17 +363,17 @@ wstring UnitConverter::Unquote(const wstring& s)
} }
else else
{ {
quotedSubString << *cursor; quotedSubString += *cursor;
unquotedString << unquoteConversions[quotedSubString.str()]; unquotedString += unquoteConversions[quotedSubString];
} }
} }
else else
{ {
unquotedString << *cursor; unquotedString += *cursor;
} }
++cursor; ++cursor;
} }
return unquotedString.str(); return unquotedString;
} }
/// <summary> /// <summary>
@ -381,16 +389,7 @@ void UnitConverter::SendCommand(Command command)
// TODO: Localization of characters // TODO: Localization of characters
bool clearFront = false; bool clearFront = false;
if (m_currentDisplay == L"0")
{
clearFront = true;
}
bool clearBack = false; bool clearBack = false;
if ((m_currentHasDecimal && m_currentDisplay.size() - 1 >= MAXIMUMDIGITSALLOWED)
|| (!m_currentHasDecimal && m_currentDisplay.size() >= MAXIMUMDIGITSALLOWED))
{
clearBack = true;
}
if (command != Command::Negate && m_switchedActive) if (command != Command::Negate && m_switchedActive)
{ {
ClearValues(); ClearValues();
@ -398,6 +397,14 @@ void UnitConverter::SendCommand(Command command)
clearFront = true; clearFront = true;
clearBack = false; clearBack = false;
} }
else
{
clearFront = (m_currentDisplay == L"0");
clearBack =
((m_currentHasDecimal && m_currentDisplay.size() - 1 >= MAXIMUMDIGITSALLOWED)
|| (!m_currentHasDecimal && m_currentDisplay.size() >= MAXIMUMDIGITSALLOWED));
}
switch (command) switch (command)
{ {
case Command::Zero: case Command::Zero:
@ -453,9 +460,9 @@ void UnitConverter::SendCommand(Command command)
case Command::Backspace: case Command::Backspace:
clearFront = false; clearFront = false;
clearBack = false; clearBack = false;
if ((m_currentDisplay.front() != '-' && m_currentDisplay.size() > 1) || m_currentDisplay.size() > 2) if ((m_currentDisplay.front() != L'-' && m_currentDisplay.size() > 1) || m_currentDisplay.size() > 2)
{ {
if (m_currentDisplay.back() == '.') if (m_currentDisplay.back() == L'.')
{ {
m_currentHasDecimal = false; m_currentHasDecimal = false;
} }
@ -473,13 +480,13 @@ void UnitConverter::SendCommand(Command command)
clearBack = false; clearBack = false;
if (m_currentCategory.supportsNegative) if (m_currentCategory.supportsNegative)
{ {
if (m_currentDisplay.front() == '-') if (m_currentDisplay.front() == L'-')
{ {
m_currentDisplay.erase(0, 1); m_currentDisplay.erase(0, 1);
} }
else else
{ {
m_currentDisplay.insert(0, 1, '-'); m_currentDisplay.insert(0, 1, L'-');
} }
} }
break; break;
@ -507,7 +514,7 @@ void UnitConverter::SendCommand(Command command)
} }
if (clearBack) if (clearBack)
{ {
m_currentDisplay.erase(m_currentDisplay.size() - 1, 1); m_currentDisplay.pop_back();
m_vmCallback->MaxDigitsReached(); m_vmCallback->MaxDigitsReached();
} }
@ -555,7 +562,7 @@ future<pair<bool, wstring>> UnitConverter::RefreshCurrencyRatios()
return async([this, currencyDataLoader, sharedLoadResult]() { return async([this, currencyDataLoader, sharedLoadResult]() {
sharedLoadResult.wait(); sharedLoadResult.wait();
bool didLoad = sharedLoadResult.get(); bool didLoad = sharedLoadResult.get();
wstring timestamp = L""; wstring timestamp;
if (currencyDataLoader != nullptr) if (currencyDataLoader != nullptr)
{ {
timestamp = currencyDataLoader->GetCurrencyTimestamp(); timestamp = currencyDataLoader->GetCurrencyTimestamp();
@ -571,11 +578,11 @@ shared_ptr<ICurrencyConverterDataLoader> UnitConverter::GetCurrencyConverterData
} }
/// <summary> /// <summary>
/// Converts a double value into another unit type, currently by multiplying by the given double ratio /// Converts a double value into another unit type
/// </summary> /// </summary>
/// <param name="value">double input value to convert</param> /// <param name="value">double input value to convert</param>
/// <param name="ratio">double conversion ratio to use</param> /// <param name="conversionData">offset and ratio to use</param>
double UnitConverter::Convert(double value, ConversionData conversionData) double UnitConverter::Convert(double value, const ConversionData& conversionData)
{ {
if (conversionData.offsetFirst) if (conversionData.offsetFirst)
{ {
@ -649,7 +656,7 @@ vector<tuple<wstring, Unit>> UnitConverter::CalculateSuggested()
if (stod(roundedString) != 0.0 || m_currentCategory.supportsNegative) if (stod(roundedString) != 0.0 || m_currentCategory.supportsNegative)
{ {
TrimTrailingZeros(roundedString); TrimTrailingZeros(roundedString);
returnVector.push_back(make_tuple(roundedString, entry.type)); returnVector.emplace_back(roundedString, entry.type);
} }
} }
@ -689,13 +696,13 @@ vector<tuple<wstring, Unit>> UnitConverter::CalculateSuggested()
if (stod(roundedString) != 0.0) if (stod(roundedString) != 0.0)
{ {
TrimTrailingZeros(roundedString); TrimTrailingZeros(roundedString);
whimsicalReturnVector.push_back(make_tuple(roundedString, entry.type)); whimsicalReturnVector.emplace_back(roundedString, entry.type);
} }
} }
// Pickup the 'best' whimsical value - currently the first one // Pickup the 'best' whimsical value - currently the first one
if (whimsicalReturnVector.size() != 0) if (!whimsicalReturnVector.empty())
{ {
returnVector.push_back(whimsicalReturnVector.at(0)); returnVector.push_back(whimsicalReturnVector.front());
} }
return returnVector; return returnVector;
@ -738,7 +745,7 @@ void UnitConverter::ResetCategoriesAndRatios()
// we just want to make sure we don't let an unready category be the default. // we just want to make sure we don't let an unready category be the default.
if (!units.empty()) if (!units.empty())
{ {
for (Unit u : units) for (const Unit& u : units)
{ {
m_ratioMap[u] = activeDataLoader->LoadOrderedRatios(u); m_ratioMap[u] = activeDataLoader->LoadOrderedRatios(u);
} }
@ -788,7 +795,7 @@ void UnitConverter::InitializeSelectedUnits()
return; return;
} }
vector<Unit> curUnits = itr->second; const vector<Unit>& curUnits = itr->second;
if (!curUnits.empty()) if (!curUnits.empty())
{ {
// Units may already have been initialized through UnitConverter::RestoreUserPreferences(). // Units may already have been initialized through UnitConverter::RestoreUserPreferences().
@ -896,8 +903,8 @@ void UnitConverter::Calculate()
} }
else else
{ {
// Fewer digits are needed following the decimal if the number is large, // Fewer digits are needed following the decimal if the number is large,
// we calculate the number of decimals necessary based on the number of digits in the integer part. // we calculate the number of decimals necessary based on the number of digits in the integer part.
precision = max(0, max(OPTIMALDIGITSALLOWED, min(MAXIMUMDIGITSALLOWED, currentNumberSignificantDigits)) - numPreDecimal); precision = max(0, max(OPTIMALDIGITSALLOWED, min(MAXIMUMDIGITSALLOWED, currentNumberSignificantDigits)) - numPreDecimal);
} }

View file

@ -50,10 +50,6 @@ namespace UnitConversionManager
accessibleName = nameValue1 + L" " + nameValue2; accessibleName = nameValue1 + L" " + nameValue2;
} }
virtual ~Unit()
{
}
int id; int id;
std::wstring name; std::wstring name;
std::wstring accessibleName; std::wstring accessibleName;
@ -145,10 +141,6 @@ namespace UnitConversionManager
{ {
} }
virtual ~ConversionData()
{
}
double ratio; double ratio;
double offset; double offset;
bool offsetFirst; bool offsetFirst;
@ -238,7 +230,7 @@ namespace UnitConversionManager
virtual void SetCurrentUnitTypes(const Unit& fromType, const Unit& toType) = 0; virtual void SetCurrentUnitTypes(const Unit& fromType, const Unit& toType) = 0;
virtual void SwitchActive(const std::wstring& newValue) = 0; virtual void SwitchActive(const std::wstring& newValue) = 0;
virtual std::wstring SaveUserPreferences() = 0; virtual std::wstring SaveUserPreferences() = 0;
virtual void RestoreUserPreferences(_In_ const std::wstring& userPreferences) = 0; virtual void RestoreUserPreferences(_In_ std::wstring_view userPreferences) = 0;
virtual void SendCommand(Command command) = 0; virtual void SendCommand(Command command) = 0;
virtual void SetViewModelCallback(_In_ const std::shared_ptr<IUnitConverterVMCallback>& newCallback) = 0; virtual void SetViewModelCallback(_In_ const std::shared_ptr<IUnitConverterVMCallback>& newCallback) = 0;
virtual void SetViewModelCurrencyCallback(_In_ const std::shared_ptr<IViewModelCurrencyCallback>& newCallback) = 0; virtual void SetViewModelCurrencyCallback(_In_ const std::shared_ptr<IViewModelCurrencyCallback>& newCallback) = 0;
@ -261,7 +253,7 @@ namespace UnitConversionManager
void SetCurrentUnitTypes(const Unit& fromType, const Unit& toType) override; void SetCurrentUnitTypes(const Unit& fromType, const Unit& toType) override;
void SwitchActive(const std::wstring& newValue) override; void SwitchActive(const std::wstring& newValue) override;
std::wstring SaveUserPreferences() override; std::wstring SaveUserPreferences() override;
void RestoreUserPreferences(const std::wstring& userPreference) override; void RestoreUserPreferences(std::wstring_view userPreference) override;
void SendCommand(Command command) override; void SendCommand(Command command) override;
void SetViewModelCallback(_In_ const std::shared_ptr<IUnitConverterVMCallback>& newCallback) override; void SetViewModelCallback(_In_ const std::shared_ptr<IUnitConverterVMCallback>& newCallback) override;
void SetViewModelCurrencyCallback(_In_ const std::shared_ptr<IViewModelCurrencyCallback>& newCallback) override; void SetViewModelCurrencyCallback(_In_ const std::shared_ptr<IViewModelCurrencyCallback>& newCallback) override;
@ -270,20 +262,20 @@ namespace UnitConversionManager
void ResetCategoriesAndRatios() override; void ResetCategoriesAndRatios() override;
// IUnitConverter // IUnitConverter
static std::vector<std::wstring> StringToVector(const std::wstring& w, const wchar_t* delimiter, bool addRemainder = false); static std::vector<std::wstring> StringToVector(std::wstring_view w, std::wstring_view delimiter, bool addRemainder = false);
static std::wstring Quote(const std::wstring& s); static std::wstring Quote(std::wstring_view s);
static std::wstring Unquote(const std::wstring& s); static std::wstring Unquote(std::wstring_view s);
private: private:
bool CheckLoad(); bool CheckLoad();
double Convert(double value, ConversionData conversionData); double Convert(double value, const ConversionData& conversionData);
std::vector<std::tuple<std::wstring, Unit>> CalculateSuggested(); std::vector<std::tuple<std::wstring, Unit>> CalculateSuggested();
void ClearValues(); void ClearValues();
void InitializeSelectedUnits(); void InitializeSelectedUnits();
Category StringToCategory(const std::wstring& w); Category StringToCategory(std::wstring_view w);
std::wstring CategoryToString(const Category& c, const wchar_t* delimiter); std::wstring CategoryToString(const Category& c, std::wstring_view delimiter);
std::wstring UnitToString(const Unit& u, const wchar_t* delimiter); std::wstring UnitToString(const Unit& u, std::wstring_view delimiter);
Unit StringToUnit(const std::wstring& w); Unit StringToUnit(std::wstring_view w);
void UpdateCurrencySymbols(); void UpdateCurrencySymbols();
void UpdateViewModel(); void UpdateViewModel();
bool AnyUnitIsEmpty(); bool AnyUnitIsEmpty();

View file

@ -327,12 +327,12 @@ namespace UnitConverterUnitTests
// Test input escaping // Test input escaping
void UnitConverterTest::UnitConverterTestQuote() void UnitConverterTest::UnitConverterTestQuote()
{ {
wstring input1 = L"Weight"; constexpr wstring_view input1 = L"Weight";
wstring output1 = L"Weight"; constexpr wstring_view output1 = L"Weight";
wstring input2 = L"{p}Weig;[ht|"; constexpr wstring_view input2 = L"{p}Weig;[ht|";
wstring output2 = L"{lb}p{rb}Weig{sc}{lc}ht{p}"; constexpr wstring_view output2 = L"{lb}p{rb}Weig{sc}{lc}ht{p}";
wstring input3 = L"{{{t;s}}},:]"; constexpr wstring_view input3 = L"{{{t;s}}},:]";
wstring output3 = L"{lb}{lb}{lb}t{sc}s{rb}{rb}{rb}{cm}{co}{rc}"; constexpr wstring_view output3 = L"{lb}{lb}{lb}t{sc}s{rb}{rb}{rb}{cm}{co}{rc}";
VERIFY_IS_TRUE(UnitConverter::Quote(input1) == output1); VERIFY_IS_TRUE(UnitConverter::Quote(input1) == output1);
VERIFY_IS_TRUE(UnitConverter::Quote(input2) == output2); VERIFY_IS_TRUE(UnitConverter::Quote(input2) == output2);
VERIFY_IS_TRUE(UnitConverter::Quote(input3) == output3); VERIFY_IS_TRUE(UnitConverter::Quote(input3) == output3);
@ -341,9 +341,9 @@ namespace UnitConverterUnitTests
// Test output unescaping // Test output unescaping
void UnitConverterTest::UnitConverterTestUnquote() void UnitConverterTest::UnitConverterTestUnquote()
{ {
wstring input1 = L"Weight"; constexpr wstring_view input1 = L"Weight";
wstring input2 = L"{p}Weig;[ht|"; constexpr wstring_view input2 = L"{p}Weig;[ht|";
wstring input3 = L"{{{t;s}}},:]"; constexpr wstring_view input3 = L"{{{t;s}}},:]";
VERIFY_IS_TRUE(UnitConverter::Unquote(input1) == input1); VERIFY_IS_TRUE(UnitConverter::Unquote(input1) == input1);
VERIFY_IS_TRUE(UnitConverter::Unquote(UnitConverter::Quote(input1)) == input1); VERIFY_IS_TRUE(UnitConverter::Unquote(UnitConverter::Quote(input1)) == input1);
VERIFY_IS_TRUE(UnitConverter::Unquote(UnitConverter::Quote(input2)) == input2); VERIFY_IS_TRUE(UnitConverter::Unquote(UnitConverter::Quote(input2)) == input2);

View file

@ -227,7 +227,7 @@ void UnitConverterMock::SwitchActive(const std::wstring& newValue)
return L"TEST"; return L"TEST";
}; };
void UnitConverterMock::RestoreUserPreferences(_In_ const std::wstring& /*userPreferences*/){}; void UnitConverterMock::RestoreUserPreferences(_In_ std::wstring_view /*userPreferences*/){};
void UnitConverterMock::SendCommand(UCM::Command command) void UnitConverterMock::SendCommand(UCM::Command command)
{ {

View file

@ -35,7 +35,7 @@ namespace CalculatorUnitTests
void SetCurrentUnitTypes(const UCM::Unit& fromType, const UCM::Unit& toType) override; void SetCurrentUnitTypes(const UCM::Unit& fromType, const UCM::Unit& toType) override;
void SwitchActive(const std::wstring& newValue); void SwitchActive(const std::wstring& newValue);
std::wstring SaveUserPreferences() override; std::wstring SaveUserPreferences() override;
void RestoreUserPreferences(_In_ const std::wstring& userPreferences) override; void RestoreUserPreferences(_In_ std::wstring_view userPreferences) override;
void SendCommand(UCM::Command command) override; void SendCommand(UCM::Command command) override;
void SetViewModelCallback(const std::shared_ptr<UCM::IUnitConverterVMCallback>& newCallback) override; void SetViewModelCallback(const std::shared_ptr<UCM::IUnitConverterVMCallback>& newCallback) override;
void SetViewModelCurrencyCallback(_In_ const std::shared_ptr<UCM::IViewModelCurrencyCallback>& /*newCallback*/) override void SetViewModelCurrencyCallback(_In_ const std::shared_ptr<UCM::IViewModelCurrencyCallback>& /*newCallback*/) override