diff --git a/test/test_equation_units.cpp b/test/test_equation_units.cpp index ddae37a8..1c13de90 100644 --- a/test/test_equation_units.cpp +++ b/test/test_equation_units.cpp @@ -594,6 +594,7 @@ TEST(otherEqUnits, unknownEQ) auto eq21 = precise_unit(precise::custom::equation_unit(22)); EXPECT_EQ(convert(1.92, eq20, precise::one), 1.92); + EXPECT_EQ(convert(1.92, precise::one, eq20), 1.92); auto conv7 = convert(7.0, eq21, eq20 * precise::W); EXPECT_TRUE(std::isnan(conv7)); diff --git a/test/test_unit_strings.cpp b/test/test_unit_strings.cpp index 5f7fdc3f..8ea92b4e 100644 --- a/test/test_unit_strings.cpp +++ b/test/test_unit_strings.cpp @@ -543,6 +543,35 @@ TEST(stringToUnits, Power) } } +TEST(stringToUnits, morePower) +{ + EXPECT_EQ(precise::us::mile.pow(2), unit_from_string("mi(USA)^(2)")); +} + +TEST(stringToUnits, specialUnits) +{ + EXPECT_EQ( + precise::percent * precise::pu * precise::kg, + unit_from_string("percentkg")); + EXPECT_EQ( + precise::percent * precise::pu * precise::kg, + unit_from_string("percentkilogram")); + EXPECT_EQ( + precise::percent * precise::pu * precise::kg, + unit_from_string("percentmass")); + EXPECT_EQ( + precise::percent * precise::pu * precise::kg, unit_from_string("%kg")); + EXPECT_EQ( + precise::percent * precise::pu * precise::kg, + unit_from_string("%kilogram")); + EXPECT_EQ( + precise::percent * precise::pu * precise::kg, + unit_from_string("%mass")); + + EXPECT_EQ(precise::pu * precise::kg, unit_from_string("perunitkilogram")); + EXPECT_EQ(precise::pu * precise::kg, unit_from_string("perunitkg")); +} + TEST(stringToUnits, mult) { EXPECT_EQ(precise::m.pow(2), unit_from_string("m*m")); @@ -730,6 +759,14 @@ TEST(stringToUnits, words) EXPECT_EQ( unit_from_string("sixty fourths of an inch"), precise_unit(1.0 / 64.0, precise::in)); + + EXPECT_EQ( + unit_from_string("sixty fourths of a mile"), + precise_unit(1.0 / 64.0, precise::mile)); + + EXPECT_EQ( + unit_from_string("thirty-seconds of a yard"), + precise_unit(1.0 / 32.0, precise::yd)); } TEST(stringToUnits, exponentForms) @@ -755,6 +792,11 @@ TEST(stringToUnits, exponentForms) unit_from_string("CM2", case_insensitive), unit_from_string("cm2")); } +TEST(stringToUnits, invalidStrings) +{ + EXPECT_FALSE(is_valid(unit_from_string("Mik"))); +} + TEST(stringToUnits, complex) { EXPECT_EQ( diff --git a/units/units.cpp b/units/units.cpp index 3fb724f1..224ab52a 100644 --- a/units/units.cpp +++ b/units/units.cpp @@ -2881,39 +2881,6 @@ static precise_unit return precise::invalid; } -// just ignore some modifiers that might be assumed in particular units -static precise_unit ignoreModifiers(std::string unit, std::uint64_t match_flags) -{ - using igpair = std::pair; - - static UNITS_CPP14_CONSTEXPR_OBJECT std::array ignore_word{{ - igpair{"liquid", 6}, - }}; - bool changed = false; - for (const auto& irep : ignore_word) { - auto fnd = unit.find(irep.first); - if (fnd != std::string::npos) { - if (irep.second == static_cast(unit.size())) { - // this is a modifier if we are checking the entire unit this is - // automatically false - return precise::invalid; - } - unit.erase(fnd, irep.second); - changed = true; - break; - } - } - if (changed) { - auto retunit = localityModifiers(unit, match_flags); - if (!is_error(retunit)) { - return retunit; - } - return unit_from_string_internal( - unit, match_flags | no_locality_modifiers | no_of_operator); - } - return precise::invalid; -} - /// detect some known SI prefixes static std::pair getPrefixMultiplierWord(const std::string& unit) @@ -4878,6 +4845,49 @@ static inline std::uint64_t getMinPartitionSize(std::uint64_t match_flags) return (match_flags & minimum_partition_size7) >> detail::minPartionSizeShift; } +static precise_unit + checkPerModifications(std::string unit_string, std::uint64_t match_flags) +{ + if (unit_string.compare(0, 7, "percent") == 0) { + auto bunit = default_unit(unit_string.substr(7)); + if (is_valid(bunit)) { + return precise::percent * precise::pu * bunit; + } + bunit = unit_from_string_internal( + unit_string.substr(7), match_flags | minimum_partition_size3); + if (is_valid(bunit)) { + return precise::percent * precise::pu * bunit; + } + } + if (unit_string.compare(0, 7, "perunit") == 0) { + auto bunit = default_unit(unit_string.substr(7)); + if (is_valid(bunit)) { + return precise::pu * bunit; + } + bunit = unit_from_string_internal( + unit_string.substr(7), match_flags | minimum_partition_size3); + if (is_valid(bunit)) { + return precise::pu * bunit; + } + } + // try changing out any "per" words for division sign + if ((match_flags & no_per_operators) == 0) { + auto fnd = findWordOperatorSep(unit_string, "per"); + if (fnd != std::string::npos) { + if (fnd == 0) { + unit_string.replace(fnd, 3, "1/"); + } else { + unit_string.replace(fnd, 3, "/"); + } + auto retunit = unit_from_string_internal( + unit_string, match_flags + per_operator1); + if (!is_error(retunit)) { + return retunit; + } + } + } + return precise::invalid; +} static precise_unit checkSpecialUnits(const std::string& unit_string, std::uint64_t match_flags) @@ -4901,35 +4911,24 @@ static precise_unit return precise::A * bunit; } } - if (unit_string.compare(0, 7, "percent") == 0) { - auto bunit = unit_from_string_internal( - unit_string.substr(7), match_flags | minimum_partition_size3); - if (is_valid(bunit)) { - return precise::percent * pu * bunit; - } - bunit = default_unit(unit_string.substr(7)); - if (is_valid(bunit)) { - return precise::percent * pu * bunit; - } - } if (unit_string.front() == '%') { - auto bunit = unit_from_string_internal( - unit_string.substr(1), match_flags | minimum_partition_size3); + auto bunit = default_unit(unit_string.substr(1)); if (is_valid(bunit)) { return precise::percent * precise::pu * bunit; } - bunit = default_unit(unit_string.substr(1)); + bunit = unit_from_string_internal( + unit_string.substr(1), match_flags | minimum_partition_size3); if (is_valid(bunit)) { return precise::percent * precise::pu * bunit; } } if (unit_string.compare(0, 7, "perunit") == 0) { - auto bunit = unit_from_string_internal( - unit_string.substr(7), match_flags | minimum_partition_size3); + auto bunit = default_unit(unit_string.substr(7)); if (is_valid(bunit)) { return precise::pu * bunit; } - bunit = default_unit(unit_string.substr(7)); + bunit = unit_from_string_internal( + unit_string.substr(7), match_flags | minimum_partition_size3); if (is_valid(bunit)) { return precise::pu * bunit; } @@ -5779,22 +5778,10 @@ static precise_unit unit_from_string_internal( } } } - - // try changing out any "per" words for division sign - if (containsPer && (match_flags & no_per_operators) == 0) { - auto fnd = findWordOperatorSep(unit_string, "per"); - if (fnd != std::string::npos) { - ustring = unit_string; - if (fnd == 0) { - ustring.replace(fnd, 3, "1/"); - } else { - ustring.replace(fnd, 3, "/"); - } - retunit = - unit_from_string_internal(ustring, match_flags + per_operator1); - if (!is_error(retunit)) { - return retunit; - } + if (containsPer) { + retunit = checkPerModifications(unit_string, match_flags); + if (is_valid(retunit)) { + return retunit; } } @@ -5830,11 +5817,10 @@ static precise_unit unit_from_string_internal( } else { sloc = ustring.find_first_of( getMatchCharacter(ustring[sloc]), sloc); - if (sloc == std::string::npos) { - ustring.push_back('}'); - } else { - ustring.insert(sloc + 1, 1, '}'); - } + ustring.insert( + (sloc == std::string::npos) ? ustring.size() : sloc + 1, + 1, + '}'); } auto cunit = @@ -5884,14 +5870,6 @@ static precise_unit unit_from_string_internal( } } - if ((match_flags & no_locality_modifiers) == 0) { - retunit = - ignoreModifiers(unit_string, match_flags | skip_partition_check); - if (!is_error(retunit)) { - return retunit; - } - } - if ((match_flags & skip_partition_check) == 0) { // check for some special partitioned units retunit = checkSpecialUnits(unit_string, match_flags);