From e7fe6be7fc0a7ab4298d285e55fe681511278bbd Mon Sep 17 00:00:00 2001 From: VPRamon Date: Mon, 23 Feb 2026 11:35:03 +0100 Subject: [PATCH 1/5] feat: Add stream insertion operator and unit symbols for various quantities --- examples/demo.cpp | 43 +++++++++++++-------------- gen_cpp_units.py | 3 +- include/qtty/ffi_core.hpp | 13 +++++++++ include/qtty/units/angular.hpp | 10 +++++++ include/qtty/units/length.hpp | 50 ++++++++++++++++++++++++++++++++ include/qtty/units/mass.hpp | 31 ++++++++++++++++++++ include/qtty/units/power.hpp | 24 ++++++++++++++++ include/qtty/units/time.hpp | 29 +++++++++++++++++++ include/qtty/units/velocity.hpp | 51 +++++++++++++++++++++++++++++++++ 9 files changed, 230 insertions(+), 24 deletions(-) diff --git a/examples/demo.cpp b/examples/demo.cpp index dcf4f43..226ab07 100644 --- a/examples/demo.cpp +++ b/examples/demo.cpp @@ -20,65 +20,62 @@ int main() { // Example 1: Basic construction and conversion std::cout << "1. Distance Conversion:" << std::endl; Meter distance(1500.0); - std::cout << " Distance: " << distance.value() << " m" << std::endl; + std::cout << " Distance: " << distance << std::endl; Kilometer km = distance.to(); - std::cout << " Distance: " << km.value() << " km" << std::endl; + std::cout << " Distance: " << km << std::endl; // Example 2: Using literals std::cout << "\n2. Using Literals:" << std::endl; auto height = 10.5_m; auto width = 5.0_m; auto area_side = height + width; - std::cout << " Height: " << height.value() << " m" << std::endl; - std::cout << " Width: " << width.value() << " m" << std::endl; - std::cout << " Sum: " << area_side.value() << " m" << std::endl; + std::cout << " Height: " << height << std::endl; + std::cout << " Width: " << width << std::endl; + std::cout << " Sum: " << area_side << std::endl; // Example 3: Velocity calculation std::cout << "\n3. Velocity Calculation:" << std::endl; auto car_distance = 100.0_km; auto travel_time = 2.0_h; auto speed = car_distance / travel_time; - std::cout << " Distance: " << car_distance.value() << " km" << std::endl; - std::cout << " Time: " << travel_time.value() << " h" << std::endl; - std::cout << " Speed: " << speed.value() << " km/h" << std::endl; + std::cout << " Distance: " << car_distance << std::endl; + std::cout << " Time: " << travel_time << std::endl; + std::cout << " Speed: " << speed << std::endl; // Example 4: Angular conversions std::cout << "\n4. Angular Conversions:" << std::endl; auto angle_deg = 180.0_deg; Radian angle_rad = angle_deg.to(); - std::cout << " Angle: " << angle_deg.value() << " degrees" << std::endl; + std::cout << " Angle: " << angle_deg << std::endl; std::cout << std::setprecision(6); - std::cout << " Angle: " << angle_rad.value() << " radians" << std::endl; + std::cout << " Angle: " << angle_rad << std::endl; // Example 5: Time conversions std::cout << "\n5. Time Conversions:" << std::endl; auto duration_seconds = 3665.0_s; Hour duration_hours = duration_seconds.to(); Minute duration_minutes = duration_seconds.to(); - std::cout << " Duration: " << duration_seconds.value() << " seconds" - << std::endl; + std::cout << " Duration: " << duration_seconds << std::endl; std::cout << std::setprecision(4); - std::cout << " Duration: " << duration_hours.value() << " hours" - << std::endl; + std::cout << " Duration: " << duration_hours << std::endl; std::cout << std::setprecision(2); - std::cout << " Duration: " << duration_minutes.value() << " minutes" - << std::endl; + std::cout << " Duration: " << duration_minutes << std::endl; // Example 6: Compound operations std::cout << "\n6. Compound Operations:" << std::endl; Meter total(100.0); - std::cout << " Initial: " << total.value() << " m" << std::endl; + std::cout << " Initial: " << total << std::endl; total += 50.0_m; - std::cout << " After += 50m: " << total.value() << " m" << std::endl; + std::cout << " After += 50m: " << total << std::endl; total *= 2.0; - std::cout << " After *= 2: " << total.value() << " m" << std::endl; + std::cout << " After *= 2: " << total << std::endl; total /= 3.0; std::cout << std::setprecision(2) << std::fixed; - std::cout << " After /= 3: " << total.value() << " m" << std::endl; + std::cout << " After /= 3: " << total << std::endl; // Example 7: Comparisons std::cout << "\n7. Comparisons:" << std::endl; @@ -94,9 +91,9 @@ int main() { Meter negative(-42.5); auto positive = negative.abs(); auto double_negative = -negative; - std::cout << " Original: " << negative.value() << " m" << std::endl; - std::cout << " Absolute: " << positive.value() << " m" << std::endl; - std::cout << " Negated: " << double_negative.value() << " m" << std::endl; + std::cout << " Original: " << negative << std::endl; + std::cout << " Absolute: " << positive << std::endl; + std::cout << " Negated: " << double_negative << std::endl; std::cout << "\n=== All examples completed successfully! ===" << std::endl; diff --git a/gen_cpp_units.py b/gen_cpp_units.py index dd47d7b..6f9583d 100755 --- a/gen_cpp_units.py +++ b/gen_cpp_units.py @@ -138,9 +138,10 @@ def generate_header_for_dimension(dimension: str, units: List[Tuple[str, str, st # Generate unit traits specializations unit_traits = [] - for const_name, name, _ in units: + for const_name, name, symbol in units: unit_traits.append(f"""template<> struct UnitTraits<{name}Tag> {{ static constexpr UnitId unit_id() {{ return UNIT_ID_{const_name}; }} + static constexpr std::string_view symbol() {{ return "{symbol}"; }} }};""") # Generate type aliases diff --git a/include/qtty/ffi_core.hpp b/include/qtty/ffi_core.hpp index e1df6c7..ba364e4 100644 --- a/include/qtty/ffi_core.hpp +++ b/include/qtty/ffi_core.hpp @@ -9,8 +9,10 @@ */ #include +#include #include #include +#include #include extern "C" { #include "qtty_ffi.h" @@ -278,4 +280,15 @@ template class Quantity { Quantity abs() const { return Quantity(std::abs(m_value)); } }; +// ============================================================================ +// Stream Insertion Operator +// ============================================================================ +// Prints a quantity with its unit symbol, e.g., "1500 m" or "42.5 km" + +template +std::ostream &operator<<(std::ostream &os, const Quantity &q) { + os << q.value() << " " << UnitTraits::symbol(); + return os; +} + } // namespace qtty diff --git a/include/qtty/units/angular.hpp b/include/qtty/units/angular.hpp index 44eea2a..5e0dbea 100644 --- a/include/qtty/units/angular.hpp +++ b/include/qtty/units/angular.hpp @@ -20,33 +20,43 @@ struct HourAngleTag {}; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_MILLIRADIAN; } + static constexpr std::string_view symbol() { return "mrad"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_RADIAN; } + static constexpr std::string_view symbol() { return "rad"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_MICRO_ARCSECOND; } + static constexpr std::string_view symbol() { return "µas"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_MILLI_ARCSECOND; } + static constexpr std::string_view symbol() { return "mas"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_ARCSECOND; } + static constexpr std::string_view symbol() { return "″"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_ARCMINUTE; } + static constexpr std::string_view symbol() { return "′"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_DEGREE; } + static constexpr std::string_view symbol() { return "°"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_GRADIAN; } + static constexpr std::string_view symbol() { return "gon"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_TURN; } + static constexpr std::string_view symbol() { return "tr"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_HOUR_ANGLE; } + static constexpr std::string_view symbol() { return "ʰ"; } }; using Milliradian = Quantity; diff --git a/include/qtty/units/length.hpp b/include/qtty/units/length.hpp index d91d78d..f0c629a 100644 --- a/include/qtty/units/length.hpp +++ b/include/qtty/units/length.hpp @@ -60,165 +60,215 @@ struct NominalSolarDiameterTag {}; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_PLANCK_LENGTH; } + static constexpr std::string_view symbol() { return "l_P"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_YOCTOMETER; } + static constexpr std::string_view symbol() { return "ym"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_ZEPTOMETER; } + static constexpr std::string_view symbol() { return "zm"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_ATTOMETER; } + static constexpr std::string_view symbol() { return "am"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_FEMTOMETER; } + static constexpr std::string_view symbol() { return "fm"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_PICOMETER; } + static constexpr std::string_view symbol() { return "pm"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_NANOMETER; } + static constexpr std::string_view symbol() { return "nm"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_MICROMETER; } + static constexpr std::string_view symbol() { return "µm"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_MILLIMETER; } + static constexpr std::string_view symbol() { return "mm"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_CENTIMETER; } + static constexpr std::string_view symbol() { return "cm"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_DECIMETER; } + static constexpr std::string_view symbol() { return "dm"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_METER; } + static constexpr std::string_view symbol() { return "m"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_DECAMETER; } + static constexpr std::string_view symbol() { return "dam"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_HECTOMETER; } + static constexpr std::string_view symbol() { return "hm"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_KILOMETER; } + static constexpr std::string_view symbol() { return "km"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_MEGAMETER; } + static constexpr std::string_view symbol() { return "Mm"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_GIGAMETER; } + static constexpr std::string_view symbol() { return "Gm"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_TERAMETER; } + static constexpr std::string_view symbol() { return "Tm"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_PETAMETER; } + static constexpr std::string_view symbol() { return "Pm"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_EXAMETER; } + static constexpr std::string_view symbol() { return "Em"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_ZETTAMETER; } + static constexpr std::string_view symbol() { return "Zm"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_YOTTAMETER; } + static constexpr std::string_view symbol() { return "Ym"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_BOHR_RADIUS; } + static constexpr std::string_view symbol() { return "a₀"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_CLASSICAL_ELECTRON_RADIUS; } + static constexpr std::string_view symbol() { return "r_e"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_ELECTRON_REDUCED_COMPTON_WAVELENGTH; } + static constexpr std::string_view symbol() { return "λ̄_e"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_ASTRONOMICAL_UNIT; } + static constexpr std::string_view symbol() { return "au"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_LIGHT_YEAR; } + static constexpr std::string_view symbol() { return "ly"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_PARSEC; } + static constexpr std::string_view symbol() { return "pc"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_KILOPARSEC; } + static constexpr std::string_view symbol() { return "kpc"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_MEGAPARSEC; } + static constexpr std::string_view symbol() { return "Mpc"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_GIGAPARSEC; } + static constexpr std::string_view symbol() { return "Gpc"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_INCH; } + static constexpr std::string_view symbol() { return "in"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_FOOT; } + static constexpr std::string_view symbol() { return "ft"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_YARD; } + static constexpr std::string_view symbol() { return "yd"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_MILE; } + static constexpr std::string_view symbol() { return "mi"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_LINK; } + static constexpr std::string_view symbol() { return "lk"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_FATHOM; } + static constexpr std::string_view symbol() { return "ftm"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_ROD; } + static constexpr std::string_view symbol() { return "rd"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_CHAIN; } + static constexpr std::string_view symbol() { return "ch"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_NAUTICAL_MILE; } + static constexpr std::string_view symbol() { return "nmi"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_NOMINAL_LUNAR_RADIUS; } + static constexpr std::string_view symbol() { return "R_☾"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_NOMINAL_LUNAR_DISTANCE; } + static constexpr std::string_view symbol() { return "LD"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_NOMINAL_EARTH_POLAR_RADIUS; } + static constexpr std::string_view symbol() { return "R_⊕pol"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_NOMINAL_EARTH_RADIUS; } + static constexpr std::string_view symbol() { return "R_⊕"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_NOMINAL_EARTH_EQUATORIAL_RADIUS; } + static constexpr std::string_view symbol() { return "R_⊕eq"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_EARTH_MERIDIONAL_CIRCUMFERENCE; } + static constexpr std::string_view symbol() { return "C_mer"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_EARTH_EQUATORIAL_CIRCUMFERENCE; } + static constexpr std::string_view symbol() { return "C_eq"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_NOMINAL_JUPITER_RADIUS; } + static constexpr std::string_view symbol() { return "R_♃"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_NOMINAL_SOLAR_RADIUS; } + static constexpr std::string_view symbol() { return "R_☉"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_NOMINAL_SOLAR_DIAMETER; } + static constexpr std::string_view symbol() { return "D_☉"; } }; using PlanckLength = Quantity; diff --git a/include/qtty/units/mass.hpp b/include/qtty/units/mass.hpp index d219756..c701cc3 100644 --- a/include/qtty/units/mass.hpp +++ b/include/qtty/units/mass.hpp @@ -41,96 +41,127 @@ struct SolarMassTag {}; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_YOCTOGRAM; } + static constexpr std::string_view symbol() { return "yg"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_ZEPTOGRAM; } + static constexpr std::string_view symbol() { return "zg"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_ATTOGRAM; } + static constexpr std::string_view symbol() { return "ag"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_FEMTOGRAM; } + static constexpr std::string_view symbol() { return "fg"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_PICOGRAM; } + static constexpr std::string_view symbol() { return "pg"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_NANOGRAM; } + static constexpr std::string_view symbol() { return "ng"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_MICROGRAM; } + static constexpr std::string_view symbol() { return "µg"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_MILLIGRAM; } + static constexpr std::string_view symbol() { return "mg"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_CENTIGRAM; } + static constexpr std::string_view symbol() { return "cg"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_DECIGRAM; } + static constexpr std::string_view symbol() { return "dg"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_GRAM; } + static constexpr std::string_view symbol() { return "g"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_DECAGRAM; } + static constexpr std::string_view symbol() { return "dag"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_HECTOGRAM; } + static constexpr std::string_view symbol() { return "hg"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_KILOGRAM; } + static constexpr std::string_view symbol() { return "kg"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_MEGAGRAM; } + static constexpr std::string_view symbol() { return "Mg"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_GIGAGRAM; } + static constexpr std::string_view symbol() { return "Gg"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_TERAGRAM; } + static constexpr std::string_view symbol() { return "Tg"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_PETAGRAM; } + static constexpr std::string_view symbol() { return "Pg"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_EXAGRAM; } + static constexpr std::string_view symbol() { return "Eg"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_ZETTAGRAM; } + static constexpr std::string_view symbol() { return "Zg"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_YOTTAGRAM; } + static constexpr std::string_view symbol() { return "Yg"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_GRAIN; } + static constexpr std::string_view symbol() { return "gr"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_OUNCE; } + static constexpr std::string_view symbol() { return "oz"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_POUND; } + static constexpr std::string_view symbol() { return "lb"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_STONE; } + static constexpr std::string_view symbol() { return "st"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_SHORT_TON; } + static constexpr std::string_view symbol() { return "ton"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_LONG_TON; } + static constexpr std::string_view symbol() { return "ton_l"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_CARAT; } + static constexpr std::string_view symbol() { return "ct"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_TONNE; } + static constexpr std::string_view symbol() { return "t"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_ATOMIC_MASS_UNIT; } + static constexpr std::string_view symbol() { return "u"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_SOLAR_MASS; } + static constexpr std::string_view symbol() { return "M_☉"; } }; using Yoctogram = Quantity; diff --git a/include/qtty/units/power.hpp b/include/qtty/units/power.hpp index f9c321a..c9608bd 100644 --- a/include/qtty/units/power.hpp +++ b/include/qtty/units/power.hpp @@ -34,75 +34,99 @@ struct SolarLuminosityTag {}; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_YOCTOWATT; } + static constexpr std::string_view symbol() { return "yW"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_ZEPTOWATT; } + static constexpr std::string_view symbol() { return "zW"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_ATTOWATT; } + static constexpr std::string_view symbol() { return "aW"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_FEMTOWATT; } + static constexpr std::string_view symbol() { return "fW"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_PICOWATT; } + static constexpr std::string_view symbol() { return "pW"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_NANOWATT; } + static constexpr std::string_view symbol() { return "nW"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_MICROWATT; } + static constexpr std::string_view symbol() { return "µW"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_MILLIWATT; } + static constexpr std::string_view symbol() { return "mW"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_DECIWATT; } + static constexpr std::string_view symbol() { return "dW"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_WATT; } + static constexpr std::string_view symbol() { return "W"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_DECAWATT; } + static constexpr std::string_view symbol() { return "daW"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_HECTOWATT; } + static constexpr std::string_view symbol() { return "hW"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_KILOWATT; } + static constexpr std::string_view symbol() { return "kW"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_MEGAWATT; } + static constexpr std::string_view symbol() { return "MW"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_GIGAWATT; } + static constexpr std::string_view symbol() { return "GW"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_TERAWATT; } + static constexpr std::string_view symbol() { return "TW"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_PETAWATT; } + static constexpr std::string_view symbol() { return "PW"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_EXAWATT; } + static constexpr std::string_view symbol() { return "EW"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_ZETTAWATT; } + static constexpr std::string_view symbol() { return "ZW"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_YOTTAWATT; } + static constexpr std::string_view symbol() { return "YW"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_ERG_PER_SECOND; } + static constexpr std::string_view symbol() { return "erg/s"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_HORSEPOWER_METRIC; } + static constexpr std::string_view symbol() { return "PS"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_HORSEPOWER_ELECTRIC; } + static constexpr std::string_view symbol() { return "hp_e"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_SOLAR_LUMINOSITY; } + static constexpr std::string_view symbol() { return "L_☉"; } }; using Yoctowatt = Quantity; diff --git a/include/qtty/units/time.hpp b/include/qtty/units/time.hpp index 9ca49d6..b0d69b3 100644 --- a/include/qtty/units/time.hpp +++ b/include/qtty/units/time.hpp @@ -39,90 +39,119 @@ struct SiderealYearTag {}; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_ATTOSECOND; } + static constexpr std::string_view symbol() { return "as"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_FEMTOSECOND; } + static constexpr std::string_view symbol() { return "fs"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_PICOSECOND; } + static constexpr std::string_view symbol() { return "ps"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_NANOSECOND; } + static constexpr std::string_view symbol() { return "ns"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_MICROSECOND; } + static constexpr std::string_view symbol() { return "µs"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_MILLISECOND; } + static constexpr std::string_view symbol() { return "ms"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_CENTISECOND; } + static constexpr std::string_view symbol() { return "cs"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_DECISECOND; } + static constexpr std::string_view symbol() { return "ds"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_SECOND; } + static constexpr std::string_view symbol() { return "s"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_DECASECOND; } + static constexpr std::string_view symbol() { return "das"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_HECTOSECOND; } + static constexpr std::string_view symbol() { return "hs"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_KILOSECOND; } + static constexpr std::string_view symbol() { return "ks"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_MEGASECOND; } + static constexpr std::string_view symbol() { return "Ms"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_GIGASECOND; } + static constexpr std::string_view symbol() { return "Gs"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_TERASECOND; } + static constexpr std::string_view symbol() { return "Ts"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_MINUTE; } + static constexpr std::string_view symbol() { return "min"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_HOUR; } + static constexpr std::string_view symbol() { return "h"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_DAY; } + static constexpr std::string_view symbol() { return "d"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_WEEK; } + static constexpr std::string_view symbol() { return "wk"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_FORTNIGHT; } + static constexpr std::string_view symbol() { return "fn"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_YEAR; } + static constexpr std::string_view symbol() { return "yr"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_DECADE; } + static constexpr std::string_view symbol() { return "dec"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_CENTURY; } + static constexpr std::string_view symbol() { return "c"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_MILLENNIUM; } + static constexpr std::string_view symbol() { return "mill"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_JULIAN_YEAR; } + static constexpr std::string_view symbol() { return "a"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_JULIAN_CENTURY; } + static constexpr std::string_view symbol() { return "jc"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_SIDEREAL_DAY; } + static constexpr std::string_view symbol() { return "sd"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_SYNODIC_MONTH; } + static constexpr std::string_view symbol() { return "mo_s"; } }; template <> struct UnitTraits { static constexpr UnitId unit_id() { return UNIT_ID_SIDEREAL_YEAR; } + static constexpr std::string_view symbol() { return "yr_s"; } }; using Attosecond = Quantity; diff --git a/include/qtty/units/velocity.hpp b/include/qtty/units/velocity.hpp index 77eac2b..c4077ba 100644 --- a/include/qtty/units/velocity.hpp +++ b/include/qtty/units/velocity.hpp @@ -61,6 +61,57 @@ operator/(const Quantity &length, const Quantity &time) { time.value()); } +// ============================================================================ +// UnitTraits for Compound Units +// ============================================================================ +// Provides symbols for common compound units. + +// Generic template specialization for CompoundTag (requires units to have +// symbols) +template +struct UnitTraits> { + // Compound units don't have a direct FFI unit ID + // Use UNIT_ID_METER as a placeholder (never actually used for conversion) + static constexpr UnitId unit_id() { return UNIT_ID_METER; } + static constexpr std::string_view symbol() { + // This is a compile-time symbol construction for compound units + // For runtime construction, we'd need to use std::string + // For now, we provide empty string as a fallback + return ""; + } +}; + +// Specializations for common velocity types +template <> struct UnitTraits> { + static constexpr UnitId unit_id() { return UNIT_ID_METER; } + static constexpr std::string_view symbol() { return "m/s"; } +}; + +template <> struct UnitTraits> { + static constexpr UnitId unit_id() { return UNIT_ID_METER; } + static constexpr std::string_view symbol() { return "km/h"; } +}; + +template <> struct UnitTraits> { + static constexpr UnitId unit_id() { return UNIT_ID_METER; } + static constexpr std::string_view symbol() { return "m/h"; } +}; + +template <> struct UnitTraits> { + static constexpr UnitId unit_id() { return UNIT_ID_METER; } + static constexpr std::string_view symbol() { return "km/s"; } +}; + +template <> struct UnitTraits> { + static constexpr UnitId unit_id() { return UNIT_ID_METER; } + static constexpr std::string_view symbol() { return "m/min"; } +}; + +template <> struct UnitTraits> { + static constexpr UnitId unit_id() { return UNIT_ID_METER; } + static constexpr std::string_view symbol() { return "km/min"; } +}; + // ============================================================================ // Common Velocity Type Aliases // ============================================================================ From 33e1f7d533c6dd23ba1da6bb0c4b1cafe6738fae Mon Sep 17 00:00:00 2001 From: VPRamon Date: Mon, 23 Feb 2026 11:41:43 +0100 Subject: [PATCH 2/5] fix: Update CMake configuration to set QTTY_FFI_FEATURES to an empty string --- .github/workflows/ci.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 225c099..00d4414 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,7 +46,7 @@ jobs: shell: bash run: | set -euo pipefail - cmake -S . -B build -G Ninja -DQTTY_BUILD_DOCS=OFF -DCMAKE_EXPORT_COMPILE_COMMANDS=ON + cmake -S . -B build -G Ninja -DQTTY_BUILD_DOCS=OFF -DQTTY_FFI_FEATURES="" -DCMAKE_EXPORT_COMPILE_COMMANDS=ON - name: clang-format check shell: bash @@ -147,7 +147,7 @@ jobs: shell: bash run: | set -euo pipefail - cmake -S . -B build -G Ninja -DQTTY_BUILD_DOCS=ON + cmake -S . -B build -G Ninja -DQTTY_BUILD_DOCS=ON -DQTTY_FFI_FEATURES="" - name: Build shell: bash @@ -205,6 +205,7 @@ jobs: set -euo pipefail cmake -S . -B build-coverage -G Ninja \ -DQTTY_BUILD_DOCS=OFF \ + -DQTTY_FFI_FEATURES="" \ -DCMAKE_BUILD_TYPE=Debug \ -DCMAKE_CXX_FLAGS="--coverage" \ -DCMAKE_EXE_LINKER_FLAGS="--coverage" From 2b3169fdbef3dd8035862e45d8d52bd4ef8a99be Mon Sep 17 00:00:00 2001 From: VPRamon Date: Mon, 23 Feb 2026 12:15:01 +0100 Subject: [PATCH 3/5] fix: Update subproject commit reference in qtty --- qtty | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qtty b/qtty index 1e26737..8140428 160000 --- a/qtty +++ b/qtty @@ -1 +1 @@ -Subproject commit 1e26737cf20c2b4653726a0ad72502e8c98d65ea +Subproject commit 814042804bce724720662bd77158b1052e922450 From 23f6b241454a077fd7cb86b7c67a052e82cbbb05 Mon Sep 17 00:00:00 2001 From: VPRamon Date: Mon, 23 Feb 2026 12:29:05 +0100 Subject: [PATCH 4/5] feat: Add .clang-format file and update CMake configuration for QTTY_FFI_FEATURES --- .clang-format | 12 ++++++++++++ .github/workflows/ci.yml | 6 +++--- 2 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..56f42d1 --- /dev/null +++ b/.clang-format @@ -0,0 +1,12 @@ +--- +Language: Cpp +BasedOnStyle: LLVM +IndentWidth: 2 +ColumnLimit: 80 +AllowShortBlocksOnASingleLine: Never +AllowShortFunctionsOnASingleLine: All +AllowShortEnumsOnASingleLine: true +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AllowShortLambdasOnASingleLine: All +AlwaysBreakTemplateDeclarations: MultiLine diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 00d4414..9afd109 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,7 +46,7 @@ jobs: shell: bash run: | set -euo pipefail - cmake -S . -B build -G Ninja -DQTTY_BUILD_DOCS=OFF -DQTTY_FFI_FEATURES="" -DCMAKE_EXPORT_COMPILE_COMMANDS=ON + cmake -S . -B build -G Ninja -DQTTY_BUILD_DOCS=OFF -DQTTY_FFI_FEATURES="serde" -DCMAKE_EXPORT_COMPILE_COMMANDS=ON - name: clang-format check shell: bash @@ -147,7 +147,7 @@ jobs: shell: bash run: | set -euo pipefail - cmake -S . -B build -G Ninja -DQTTY_BUILD_DOCS=ON -DQTTY_FFI_FEATURES="" + cmake -S . -B build -G Ninja -DQTTY_BUILD_DOCS=ON -DQTTY_FFI_FEATURES="serde" - name: Build shell: bash @@ -205,7 +205,7 @@ jobs: set -euo pipefail cmake -S . -B build-coverage -G Ninja \ -DQTTY_BUILD_DOCS=OFF \ - -DQTTY_FFI_FEATURES="" \ + -DQTTY_FFI_FEATURES="serde" \ -DCMAKE_BUILD_TYPE=Debug \ -DCMAKE_CXX_FLAGS="--coverage" \ -DCMAKE_EXE_LINKER_FLAGS="--coverage" From 26a7359c1454a07ec2fe7c452c660f95993ac58b Mon Sep 17 00:00:00 2001 From: VPRamon Date: Mon, 23 Feb 2026 12:33:05 +0100 Subject: [PATCH 5/5] feat: Install clang-format 18 in CI workflow --- .github/workflows/ci.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9afd109..b44be2c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,9 +34,18 @@ jobs: sudo apt-get install -y --no-install-recommends \ cmake \ ninja-build \ - clang-format \ clang-tidy + - name: Install clang-format 18 + shell: bash + run: | + set -euo pipefail + wget -qO /tmp/llvm.sh https://apt.llvm.org/llvm.sh + sudo bash /tmp/llvm.sh 18 + sudo apt-get install -y --no-install-recommends clang-format-18 + sudo ln -sf /usr/bin/clang-format-18 /usr/local/bin/clang-format + clang-format --version + - name: Set up Rust (stable) uses: actions-rust-lang/setup-rust-toolchain@v1 with: