diff --git a/config/cppcheck_suppressions.txt b/config/cppcheck_suppressions.txt index 8d7178a6..2cf3e9bd 100644 --- a/config/cppcheck_suppressions.txt +++ b/config/cppcheck_suppressions.txt @@ -3,7 +3,7 @@ unusedFunction:units/x12_conv.cpp:1009 passedByValue:units/units.cpp:224 passedByValue:units/units.cpp:1160 passedByValue:units/units.cpp:1177 -passedByValue:units/units.cpp:3067 +passedByValue:units/units.cpp:3069 passedByValue:units/units.hpp:413 passedByValue:units/units.hpp:590 passedByValue:units/units.hpp:1020 diff --git a/python/units_python.cpp b/python/units_python.cpp index 9d322217..90e0e4ee 100644 --- a/python/units_python.cpp +++ b/python/units_python.cpp @@ -732,7 +732,7 @@ NB_MODULE(units_llnl_ext, mod) units::precise::generate_custom_count_unit( static_cast(value)); } else { - def = def * (units::unit_from_string(key).pow(value)); + def = def * (units::default_unit(key).pow(value)); } } new (dim) Dimension{def}; @@ -827,34 +827,34 @@ NB_MODULE(units_llnl_ext, mod) } if (!custom) { if (base.meter() != 0) { - dictionary["meters"] = base.meter(); + dictionary["Length"] = base.meter(); } if (base.kg() != 0) { - dictionary["kilogram"] = base.kg(); + dictionary["Mass"] = base.kg(); } if (base.second() != 0) { - dictionary["second"] = base.second(); + dictionary["Time"] = base.second(); } if (base.ampere() != 0) { - dictionary["ampere"] = base.ampere(); + dictionary["Electric Current"] = base.ampere(); } if (base.kelvin() != 0) { - dictionary["kelvin"] = base.kelvin(); + dictionary["Temperature"] = base.kelvin(); } if (base.mole() != 0) { - dictionary["mole"] = base.mole(); + dictionary["Amount of Substance"] = base.mole(); } if (base.candela() != 0) { - dictionary["candela"] = base.candela(); + dictionary["Luminous Intensity"] = base.candela(); } if (base.currency() != 0) { - dictionary["currency"] = base.currency(); + dictionary["Currency"] = base.currency(); } if (base.count() != 0) { - dictionary["count"] = base.count(); + dictionary["Count"] = base.count(); } if (base.radian() != 0) { - dictionary["radian"] = base.radian(); + dictionary["Angle"] = base.radian(); } if (base.is_per_unit()) { dictionary["per_unit"] = 1; diff --git a/test/python/test_dimensions.py b/test/python/test_dimensions.py index afad18b6..3ffdb42b 100644 --- a/test/python/test_dimensions.py +++ b/test/python/test_dimensions.py @@ -78,15 +78,16 @@ def test_dimensions_decompose1(): d1 = Dimension("volume") decomposition = d1.decompose() - assert decomposition["meters"] == 3 + assert decomposition["Length"] == 3 def test_dimensions_decompose2(): u1 = Unit("$ per watt radian") dim = u1.dimension decomposition = dim.decompose() - + print(f"dim={decomposition}") dim2 = Dimension(decomposition) + print(f"dim2={dim2.decompose()}") assert dim2 == dim assert dim2.default_unit == u1 diff --git a/test/test_measurement.cpp b/test/test_measurement.cpp index ed58d5d9..f92f770e 100644 --- a/test/test_measurement.cpp +++ b/test/test_measurement.cpp @@ -499,16 +499,6 @@ TEST(PreciseMeasurement, unaryOps) EXPECT_EQ(z.units(), x.units()); } -TEST(PreciseMeasurement, countAddition) -{ - auto m1 = 1.0 * precise::Hz; - auto m2 = 1.0 * unit_from_string("baud"); - auto m3 = 1.0 * precise::Bq; - - auto m4 = m1 + m2 + m3; - auto str = to_string(m4); -} - TEST(PreciseMeasurement, doubleOps) { auto freq = 9.0 / precise::s; diff --git a/test/test_measurement_strings.cpp b/test/test_measurement_strings.cpp index d98f854d..84c4525c 100644 --- a/test/test_measurement_strings.cpp +++ b/test/test_measurement_strings.cpp @@ -75,6 +75,31 @@ TEST(MeasurementToString, simple) EXPECT_EQ(to_string(meas), "45 m"); } +TEST(PreciseMeasurement, countAddition) +{ + auto m1 = 1.0 * precise::Hz; + auto m2 = 1.0 * unit_from_string("baud"); + auto m3 = 1.0 * precise::Bq; + + auto m4 = m1 + m2 + m3; + auto str = to_string(m4); +} + +TEST(MeasurementToString, one) +{ + auto s1 = to_string( + units::precise_measurement(10, units::precise_unit(units::one))); + EXPECT_EQ(s1, "10"); + auto s2 = to_string( + units::precise_measurement(0, units::precise_unit(units::one))); + EXPECT_EQ(s2, "0"); + + auto s3 = to_string(units::measurement(10, units::unit(units::one))); + EXPECT_EQ(s3, "10"); + auto s4 = to_string(units::measurement(0, units::unit(units::one))); + EXPECT_EQ(s4, "0"); +} + TEST(MeasurementToString, test) { measurement density = 10.0 * kg / m.pow(3); diff --git a/units/units.cpp b/units/units.cpp index 020e1361..1dd3215f 100644 --- a/units/units.cpp +++ b/units/units.cpp @@ -1744,13 +1744,15 @@ std::string std::stringstream ss; ss.precision(12); ss << measure.value(); - ss << ' '; auto str = to_string(measure.units(), match_flags); - if (isNumericalStartCharacter(str.front())) { - str.insert(str.begin(), '('); - str.push_back(')'); + if (!str.empty()) { + ss << ' '; + if (isNumericalStartCharacter(str.front())) { + str.insert(str.begin(), '('); + str.push_back(')'); + } + ss << str; } - ss << str; return ss.str(); } @@ -4906,29 +4908,33 @@ static precise_unit static precise_unit checkSpecialUnits(const std::string& unit_string, std::uint64_t match_flags) { + precise_unit bunit; // lets try checking for meter next which is one of the most common // reasons for getting here auto fnd = findWordOperatorSep(unit_string, "meter"); if (fnd != std::string::npos) { std::string ustring = unit_string; ustring.erase(fnd, 5); - auto bunit = unit_from_string_internal(ustring, match_flags); + bunit = unit_from_string_internal(ustring, match_flags); if (is_valid(bunit)) { return precise::m * bunit; } } + // detect another somewhat common situation often amphour or ampsecond if (unit_string.compare(0, 3, "amp") == 0) { - auto bunit = unit_from_string_internal( + bunit = unit_from_string_internal( unit_string.substr(3), match_flags | minimum_partition_size3); if (is_valid(bunit)) { return precise::A * bunit; } } if (unit_string.front() == '%') { - auto bunit = default_unit(unit_string.substr(1)); - if (is_valid(bunit)) { - return precise::percent * precise::pu * bunit; + if ((match_flags & no_default_units) == 0) { + bunit = default_unit(unit_string.substr(1)); + if (is_valid(bunit)) { + return precise::percent * precise::pu * bunit; + } } bunit = unit_from_string_internal( unit_string.substr(1), match_flags | minimum_partition_size3); @@ -4937,9 +4943,11 @@ static precise_unit } } if (unit_string.compare(0, 2, "pu") == 0) { - auto bunit = default_unit(unit_string.substr(2)); - if (is_valid(bunit)) { - return precise::pu * bunit; + if ((match_flags & no_default_units) == 0) { + bunit = default_unit(unit_string.substr(2)); + if (is_valid(bunit)) { + return precise::pu * bunit; + } } bunit = unit_from_string_internal( unit_string.substr(2), match_flags | minimum_partition_size3); @@ -5542,9 +5550,11 @@ static precise_unit unit_from_string_internal( if (!is_valid(b_unit)) { if ((unit_string[sep] == '*') && (a_unit == precise::pu || a_unit == precise::percent)) { - b_unit = default_unit(unit_string.substr(sep + 1)); - if (is_valid(b_unit)) { - return a_unit * b_unit; + if ((match_flags & no_default_units) == 0) { + b_unit = default_unit(unit_string.substr(sep + 1)); + if (is_valid(b_unit)) { + return a_unit * b_unit; + } } } return precise::invalid; @@ -6119,6 +6129,9 @@ precise_unit default_unit(std::string unit_type) if (unit_type.compare(0, 10, "quantityof") == 0) { return default_unit(unit_type.substr(10)); } + if (unit_type.compare(0, 9, "measureof") == 0) { + return default_unit(unit_type.substr(9)); + } if (unit_type.compare(0, 6, "rateof") == 0) { return default_unit(unit_type.substr(6)) / precise::s; } @@ -6169,6 +6182,10 @@ precise_unit default_unit(std::string unit_type) unit_type.substr(0, unit_type.size() - strlen("rate"))) / precise::s; } + auto retunit = unit_from_string(unit_type, no_default_units); + if (is_valid(retunit)) { + return precise_unit(retunit.base_units()); + } return precise::invalid; } diff --git a/units/units.hpp b/units/units.hpp index b9675c17..40413ff3 100644 --- a/units/units.hpp +++ b/units/units.hpp @@ -1933,7 +1933,8 @@ enum unit_conversion_flags : std::uint64_t { (1U << 24U), // counter for skipping commodity check vi of // nothing at 25, 24 through 26 are connected no_commodities = (1U << 26U), //!< skip commodity checks - // 27-31 are unused as of yet + no_default_units = (1U << 27U), //!< skip any check of default unit types + // 28-31 are unused as of yet partition_check1 = (1ULL << 32U), //!< counter for skipping partitioning // nothing at 28, 27 through 29 are connected to limit partition // depth diff --git a/units/units_conversion_maps.hpp b/units/units_conversion_maps.hpp index 85b73eb9..5aee85db 100644 --- a/units/units_conversion_maps.hpp +++ b/units/units_conversion_maps.hpp @@ -3248,7 +3248,7 @@ std::array, 233> // Mostly from https://en.wikipedia.org/wiki/International_System_of_Units UNITS_CPP14_CONSTEXPR_OBJECT -std::array, 247> defined_measurement_types{ +std::array, 251> defined_measurement_types{ { {"", precise::defunit}, {"arb", precise::defunit}, @@ -3283,8 +3283,8 @@ std::array, 247> defined_measurement_types{ {"temp", precise::K}, {"thermodynamictemperature", precise::K}, {"thermalconductivity", precise::W / precise::m / precise::K}, - {"amount", precise::mol}, {"amountofsubstance", precise::mol}, + {"amount", precise::mol}, {"substance", precise::mol}, {"sub", precise::mol}, {"luminousintensity", precise::cd}, @@ -3498,5 +3498,9 @@ std::array, 247> defined_measurement_types{ {"information", precise::bit}, {"unitless", precise::one}, {"numeric", precise::one}, + {"currency", precise::currency}, + {"value", precise::currency}, + {"money", precise::currency}, + {"count", precise::count}, }}; } // namespace UNITS_NAMESPACE