From 29a97e70ebe991ae080f6f441a32c9af7477aeba Mon Sep 17 00:00:00 2001 From: VPRamon Date: Tue, 24 Feb 2026 01:48:59 +0100 Subject: [PATCH 01/10] feat: Add stream insertion operator for Quantity type --- include/qtty/ffi_core.hpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/include/qtty/ffi_core.hpp b/include/qtty/ffi_core.hpp index f58213f..4ffd810 100644 --- a/include/qtty/ffi_core.hpp +++ b/include/qtty/ffi_core.hpp @@ -4,6 +4,7 @@ #include #include #include +#include extern "C" { #include "qtty_ffi.h" } @@ -265,6 +266,16 @@ 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 From 79fd7652dccf3341689d4a490a01c40302d3d17a Mon Sep 17 00:00:00 2001 From: VPRamon Date: Tue, 24 Feb 2026 02:03:00 +0100 Subject: [PATCH 02/10] Add unit symbols and SPDX license to mass, power, time, and velocity units - Enhanced UnitTraits for mass units (e.g., Yoctogram, Kilogram) to include symbol definitions. - Added SPDX license header to mass.hpp, power.hpp, time.hpp, and velocity.hpp files. - Updated UnitTraits for power units (e.g., Yoctowatt, Kilowatt) to include symbol definitions. - Enhanced UnitTraits for time units (e.g., Attosecond, Minute) to include symbol definitions. - Introduced support for compound units in velocity, including common velocity types with appropriate symbols. --- include/qtty/ffi_core.hpp | 8 +- include/qtty/units/angular.hpp | 10 + include/qtty/units/length.hpp | 366 +++++++++++++++++++------------- include/qtty/units/mass.hpp | 158 ++++++++------ include/qtty/units/power.hpp | 123 ++++++----- include/qtty/units/time.hpp | 148 ++++++++----- include/qtty/units/velocity.hpp | 73 ++++++- 7 files changed, 556 insertions(+), 330 deletions(-) diff --git a/include/qtty/ffi_core.hpp b/include/qtty/ffi_core.hpp index 4ffd810..1f75677 100644 --- a/include/qtty/ffi_core.hpp +++ b/include/qtty/ffi_core.hpp @@ -80,7 +80,10 @@ class Quantity; // its corresponding C FFI unit ID constant (e.g., UNIT_ID_METER). // Specializations are auto-generated in include/qtty/units/*.hpp template -struct UnitTraits; +struct UnitTraits { + // Default symbol returns empty string. Specialize for units that have symbols. + static constexpr std::string_view symbol() { return ""; } +}; // Helper to extract tag from either a tag or Quantity // This allows .to<>() to accept both Quantity and KilometerTag, @@ -266,11 +269,12 @@ 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" +// Prints a quantity's value (with unit symbol support for units that define it). template std::ostream &operator<<(std::ostream &os, const Quantity &q) { diff --git a/include/qtty/units/angular.hpp b/include/qtty/units/angular.hpp index 5476fa5..dbe8eb2 100644 --- a/include/qtty/units/angular.hpp +++ b/include/qtty/units/angular.hpp @@ -17,33 +17,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 bd4f9b9..f0c629a 100644 --- a/include/qtty/units/length.hpp +++ b/include/qtty/units/length.hpp @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// Copyright (C) 2026 Vallés Puig, Ramon + #pragma once #include "../ffi_core.hpp" @@ -55,155 +58,217 @@ struct NominalJupiterRadiusTag {}; struct NominalSolarRadiusTag {}; struct NominalSolarDiameterTag {}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_PLANCK_LENGTH; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_YOCTOMETER; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_ZEPTOMETER; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_ATTOMETER; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_FEMTOMETER; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_PICOMETER; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_NANOMETER; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_MICROMETER; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_MILLIMETER; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_CENTIMETER; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_DECIMETER; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_METER; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_DECAMETER; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_HECTOMETER; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_KILOMETER; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_MEGAMETER; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_GIGAMETER; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_TERAMETER; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_PETAMETER; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_EXAMETER; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_ZETTAMETER; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_YOTTAMETER; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_BOHR_RADIUS; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_CLASSICAL_ELECTRON_RADIUS; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_ELECTRON_REDUCED_COMPTON_WAVELENGTH; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_ASTRONOMICAL_UNIT; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_LIGHT_YEAR; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_PARSEC; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_KILOPARSEC; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_MEGAPARSEC; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_GIGAPARSEC; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_INCH; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_FOOT; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_YARD; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_MILE; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_LINK; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_FATHOM; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_ROD; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_CHAIN; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_NAUTICAL_MILE; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_NOMINAL_LUNAR_RADIUS; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_NOMINAL_LUNAR_DISTANCE; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_NOMINAL_EARTH_POLAR_RADIUS; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_NOMINAL_EARTH_RADIUS; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_NOMINAL_EARTH_EQUATORIAL_RADIUS; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_EARTH_MERIDIONAL_CIRCUMFERENCE; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_EARTH_EQUATORIAL_CIRCUMFERENCE; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_NOMINAL_JUPITER_RADIUS; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_NOMINAL_SOLAR_RADIUS; } -}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_NOMINAL_SOLAR_DIAMETER; } +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; @@ -230,7 +295,8 @@ using Zettameter = Quantity; using Yottameter = Quantity; using BohrRadius = Quantity; using ClassicalElectronRadius = Quantity; -using ElectronReducedComptonWavelength = Quantity; +using ElectronReducedComptonWavelength = + Quantity; using AstronomicalUnit = Quantity; using LightYear = Quantity; using Parsec = Quantity; diff --git a/include/qtty/units/mass.hpp b/include/qtty/units/mass.hpp index eb9ea46..c701cc3 100644 --- a/include/qtty/units/mass.hpp +++ b/include/qtty/units/mass.hpp @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// Copyright (C) 2026 Vallés Puig, Ramon + #pragma once #include "../ffi_core.hpp" @@ -36,98 +39,129 @@ struct TonneTag {}; struct AtomicMassUnitTag {}; struct SolarMassTag {}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_YOCTOGRAM; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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 1edb907..c9608bd 100644 --- a/include/qtty/units/power.hpp +++ b/include/qtty/units/power.hpp @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// Copyright (C) 2026 Vallés Puig, Ramon + #pragma once #include "../ffi_core.hpp" @@ -29,77 +32,101 @@ struct HorsepowerMetricTag {}; struct HorsepowerElectricTag {}; struct SolarLuminosityTag {}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_YOCTOWATT; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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 99c166f..b0d69b3 100644 --- a/include/qtty/units/time.hpp +++ b/include/qtty/units/time.hpp @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// Copyright (C) 2026 Vallés Puig, Ramon + #pragma once #include "../ffi_core.hpp" @@ -34,92 +37,121 @@ struct SiderealDayTag {}; struct SynodicMonthTag {}; struct SiderealYearTag {}; -template<> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_ATTOSECOND; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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; } +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 b774b96..c4077ba 100644 --- a/include/qtty/units/velocity.hpp +++ b/include/qtty/units/velocity.hpp @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// Copyright (C) 2026 Vallés Puig, Ramon + #pragma once #include "../ffi_core.hpp" @@ -23,14 +26,14 @@ namespace qtty { // denominator separately, then recombine. // Template for compound units (e.g., velocity = length/time) -template -struct CompoundTag {}; +template struct CompoundTag {}; // Velocity type alias using compound units // This is a template alias, not a concrete type. Instantiate with specific // length and time units, e.g., Velocity. -template -using Velocity = Quantity>; +template +using Velocity = Quantity< + CompoundTag>; // Note: The C API doesn't have explicit velocity unit IDs // We create velocity by dividing length by time, operating on raw values @@ -51,14 +54,64 @@ using Velocity = Quantity -Quantity> operator/( - const Quantity& length, - const Quantity& time) -{ - return Quantity>(length.value() / time.value()); +template +Quantity> +operator/(const Quantity &length, const Quantity &time) { + return Quantity>(length.value() / + 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 bc8d646ba4c2937566e0df9998171531ae6a573d Mon Sep 17 00:00:00 2001 From: VPRamon Date: Tue, 24 Feb 2026 02:07:20 +0100 Subject: [PATCH 03/10] Refactor and enhance qtty library with improved documentation and serialization support - Added SPDX license and copyright information to all relevant files. - Improved documentation in `qtty.hpp` and `serialization.hpp` for better clarity on usage and functionality. - Reordered includes in `qtty.hpp` and `serialization.hpp` for consistency. - Simplified inline functions in `qtty.hpp` and `serialization.hpp` for better readability. - Enhanced JSON serialization and deserialization functions to ensure robust error handling. - Added unit tests for serialization in `test_serialization.cpp` to validate JSON round-trip conversions. - Updated tests across various dimensions (length, mass, time, etc.) for consistency in formatting and readability. - Ensured all test cases utilize modern C++ practices for better maintainability. --- qtty | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qtty b/qtty index 8140428..1e26737 160000 --- a/qtty +++ b/qtty @@ -1 +1 @@ -Subproject commit 814042804bce724720662bd77158b1052e922450 +Subproject commit 1e26737cf20c2b4653726a0ad72502e8c98d65ea From 15670275a1f4c29a20f63e737ebb6dfc139e52ca Mon Sep 17 00:00:00 2001 From: VPRamon Date: Tue, 24 Feb 2026 02:12:18 +0100 Subject: [PATCH 04/10] refactor: Clean up includes and improve formatting in ffi_core.hpp and angular.hpp --- include/qtty/ffi_core.hpp | 17 +++++----- include/qtty/units/angular.hpp | 60 +++++++++++++++++----------------- 2 files changed, 39 insertions(+), 38 deletions(-) diff --git a/include/qtty/ffi_core.hpp b/include/qtty/ffi_core.hpp index 653649c..51408b4 100644 --- a/include/qtty/ffi_core.hpp +++ b/include/qtty/ffi_core.hpp @@ -10,11 +10,11 @@ #include #include +#include #include #include #include #include -#include extern "C" { #include "qtty_ffi.h" } @@ -107,10 +107,10 @@ template class Quantity; // Each unit tag (e.g., MeterTag) must specialize this template to provide // its corresponding C FFI unit ID constant (e.g., UNIT_ID_METER). // Specializations are auto-generated in include/qtty/units/*.hpp -template -struct UnitTraits { - // Default symbol returns empty string. Specialize for units that have symbols. - static constexpr std::string_view symbol() { return ""; } +template struct UnitTraits { + // Default symbol returns empty string. Specialize for units that have + // symbols. + static constexpr std::string_view symbol() { return ""; } }; // Helper to extract tag from either a tag or Quantity @@ -288,12 +288,13 @@ template class Quantity { // ============================================================================ // Stream Insertion Operator // ============================================================================ -// Prints a quantity's value (with unit symbol support for units that define it). +// Prints a quantity's value (with unit symbol support for units that define +// it). template std::ostream &operator<<(std::ostream &os, const Quantity &q) { - os << q.value() << " " << UnitTraits::symbol(); - return os; + os << q.value() << " " << UnitTraits::symbol(); + return os; } } // namespace qtty diff --git a/include/qtty/units/angular.hpp b/include/qtty/units/angular.hpp index c20e755..5e0dbea 100644 --- a/include/qtty/units/angular.hpp +++ b/include/qtty/units/angular.hpp @@ -18,45 +18,45 @@ struct GradianTag {}; struct TurnTag {}; 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_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_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_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_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_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_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_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_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_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 "ʰ"; } +template <> struct UnitTraits { + static constexpr UnitId unit_id() { return UNIT_ID_HOUR_ANGLE; } + static constexpr std::string_view symbol() { return "ʰ"; } }; using Milliradian = Quantity; From 62dd9a5cf8827c93a72f2579c5a6bd83c6410340 Mon Sep 17 00:00:00 2001 From: VPRamon Date: Tue, 24 Feb 2026 02:16:38 +0100 Subject: [PATCH 05/10] fix: Disable default Cargo features for qtty-ffi in CMakeLists.txt --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ff5e16a..06c3770 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ set(QTTY_ARTIFACT_DIR ${QTTY_SUBMODULE_DIR}/target/release) # Allow enabling Cargo features for qtty-ffi (e.g., serde) # Use a STRING cache var (not BOOL) so users can set: "serde", "", or custom lists. -set(QTTY_FFI_FEATURES "serde" CACHE STRING "Cargo features for qtty-ffi (e.g., 'serde' or empty)") +set(QTTY_FFI_FEATURES "" CACHE STRING "Cargo features for qtty-ffi (e.g., 'serde' or empty)") # Normalize feature args: treat OFF/FALSE/0 as empty; ON means default 'serde'. set(_QTTY_FEATURES_ARGS "") From 5a24b6073d24f1348b55781dab8e5053b19d8a2f Mon Sep 17 00:00:00 2001 From: VPRamon Date: Tue, 24 Feb 2026 02:22:09 +0100 Subject: [PATCH 06/10] refactor: Simplify feature argument handling in CMakeLists.txt --- CMakeLists.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 06c3770..a788665 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,13 +18,11 @@ set(QTTY_ARTIFACT_DIR ${QTTY_SUBMODULE_DIR}/target/release) # Use a STRING cache var (not BOOL) so users can set: "serde", "", or custom lists. set(QTTY_FFI_FEATURES "" CACHE STRING "Cargo features for qtty-ffi (e.g., 'serde' or empty)") -# Normalize feature args: treat OFF/FALSE/0 as empty; ON means default 'serde'. +# Normalize feature args: treat OFF/FALSE/0 as empty. set(_QTTY_FEATURES_ARGS "") string(TOUPPER "${QTTY_FFI_FEATURES}" _QTTY_FEATURES_UP) if("${_QTTY_FEATURES_UP}" STREQUAL "OFF" OR "${_QTTY_FEATURES_UP}" STREQUAL "FALSE" OR "${_QTTY_FEATURES_UP}" STREQUAL "0") # No features -elseif("${_QTTY_FEATURES_UP}" STREQUAL "ON") - set(_QTTY_FEATURES_ARGS --features serde) elseif(NOT "${QTTY_FFI_FEATURES}" STREQUAL "") set(_QTTY_FEATURES_ARGS --features ${QTTY_FFI_FEATURES}) endif() From 1caa8a762af495256101fe1e8b3355d7d38daad1 Mon Sep 17 00:00:00 2001 From: VPRamon Date: Tue, 24 Feb 2026 18:59:04 +0100 Subject: [PATCH 07/10] feat: Add Doxygen configuration and documentation for qtty-cpp - Created CMakeDoxyfile.in for Doxygen configuration generation. - Added Doxyfile.qtty_cpp for project-specific Doxygen settings. - Updated main.rs to allow for an optional 6th field in CSV parsing. - Enhanced ffi_core.hpp with compound unit type traits and conversion logic. - Modified literals.hpp to include angular units and clean up operator overloads. - Expanded serialization.hpp to support JSON serialization/deserialization for derived quantities. - Updated length.hpp and velocity.hpp to improve compound unit handling and conversions. - Added comprehensive tests for derived quantities, including conversion and arithmetic operations. --- build-coverage/CMakeDoxyfile.in | 298 +++++++++++++++++++++++++++++++ build-coverage/Doxyfile.qtty_cpp | 65 +++++++ gen_cpp_units/src/main.rs | 8 +- include/qtty/ffi_core.hpp | 53 ++++-- include/qtty/literals.hpp | 19 +- include/qtty/serialization.hpp | 61 +++++++ include/qtty/units/length.hpp | 27 +-- include/qtty/units/velocity.hpp | 68 +++---- tests/test_derived.cpp | 45 +++++ 9 files changed, 564 insertions(+), 80 deletions(-) create mode 100644 build-coverage/CMakeDoxyfile.in create mode 100644 build-coverage/Doxyfile.qtty_cpp diff --git a/build-coverage/CMakeDoxyfile.in b/build-coverage/CMakeDoxyfile.in new file mode 100644 index 0000000..041b254 --- /dev/null +++ b/build-coverage/CMakeDoxyfile.in @@ -0,0 +1,298 @@ +# +# DO NOT EDIT! THIS FILE WAS GENERATED BY CMAKE! +# + +DOXYFILE_ENCODING = @DOXYGEN_DOXYFILE_ENCODING@ +PROJECT_NAME = @DOXYGEN_PROJECT_NAME@ +PROJECT_NUMBER = @DOXYGEN_PROJECT_NUMBER@ +PROJECT_BRIEF = @DOXYGEN_PROJECT_BRIEF@ +PROJECT_LOGO = @DOXYGEN_PROJECT_LOGO@ +OUTPUT_DIRECTORY = @DOXYGEN_OUTPUT_DIRECTORY@ +CREATE_SUBDIRS = @DOXYGEN_CREATE_SUBDIRS@ +CREATE_SUBDIRS_LEVEL = @DOXYGEN_CREATE_SUBDIRS_LEVEL@ +ALLOW_UNICODE_NAMES = @DOXYGEN_ALLOW_UNICODE_NAMES@ +OUTPUT_LANGUAGE = @DOXYGEN_OUTPUT_LANGUAGE@ +BRIEF_MEMBER_DESC = @DOXYGEN_BRIEF_MEMBER_DESC@ +REPEAT_BRIEF = @DOXYGEN_REPEAT_BRIEF@ +ABBREVIATE_BRIEF = @DOXYGEN_ABBREVIATE_BRIEF@ +ALWAYS_DETAILED_SEC = @DOXYGEN_ALWAYS_DETAILED_SEC@ +INLINE_INHERITED_MEMB = @DOXYGEN_INLINE_INHERITED_MEMB@ +FULL_PATH_NAMES = @DOXYGEN_FULL_PATH_NAMES@ +STRIP_FROM_PATH = @DOXYGEN_STRIP_FROM_PATH@ +STRIP_FROM_INC_PATH = @DOXYGEN_STRIP_FROM_INC_PATH@ +SHORT_NAMES = @DOXYGEN_SHORT_NAMES@ +JAVADOC_AUTOBRIEF = @DOXYGEN_JAVADOC_AUTOBRIEF@ +JAVADOC_BANNER = @DOXYGEN_JAVADOC_BANNER@ +QT_AUTOBRIEF = @DOXYGEN_QT_AUTOBRIEF@ +MULTILINE_CPP_IS_BRIEF = @DOXYGEN_MULTILINE_CPP_IS_BRIEF@ +PYTHON_DOCSTRING = @DOXYGEN_PYTHON_DOCSTRING@ +INHERIT_DOCS = @DOXYGEN_INHERIT_DOCS@ +SEPARATE_MEMBER_PAGES = @DOXYGEN_SEPARATE_MEMBER_PAGES@ +TAB_SIZE = @DOXYGEN_TAB_SIZE@ +ALIASES = @DOXYGEN_ALIASES@ +OPTIMIZE_OUTPUT_FOR_C = @DOXYGEN_OPTIMIZE_OUTPUT_FOR_C@ +OPTIMIZE_OUTPUT_JAVA = @DOXYGEN_OPTIMIZE_OUTPUT_JAVA@ +OPTIMIZE_FOR_FORTRAN = @DOXYGEN_OPTIMIZE_FOR_FORTRAN@ +OPTIMIZE_OUTPUT_VHDL = @DOXYGEN_OPTIMIZE_OUTPUT_VHDL@ +OPTIMIZE_OUTPUT_SLICE = @DOXYGEN_OPTIMIZE_OUTPUT_SLICE@ +EXTENSION_MAPPING = @DOXYGEN_EXTENSION_MAPPING@ +MARKDOWN_SUPPORT = @DOXYGEN_MARKDOWN_SUPPORT@ +TOC_INCLUDE_HEADINGS = @DOXYGEN_TOC_INCLUDE_HEADINGS@ +MARKDOWN_ID_STYLE = @DOXYGEN_MARKDOWN_ID_STYLE@ +AUTOLINK_SUPPORT = @DOXYGEN_AUTOLINK_SUPPORT@ +BUILTIN_STL_SUPPORT = @DOXYGEN_BUILTIN_STL_SUPPORT@ +CPP_CLI_SUPPORT = @DOXYGEN_CPP_CLI_SUPPORT@ +SIP_SUPPORT = @DOXYGEN_SIP_SUPPORT@ +IDL_PROPERTY_SUPPORT = @DOXYGEN_IDL_PROPERTY_SUPPORT@ +DISTRIBUTE_GROUP_DOC = @DOXYGEN_DISTRIBUTE_GROUP_DOC@ +GROUP_NESTED_COMPOUNDS = @DOXYGEN_GROUP_NESTED_COMPOUNDS@ +SUBGROUPING = @DOXYGEN_SUBGROUPING@ +INLINE_GROUPED_CLASSES = @DOXYGEN_INLINE_GROUPED_CLASSES@ +INLINE_SIMPLE_STRUCTS = @DOXYGEN_INLINE_SIMPLE_STRUCTS@ +TYPEDEF_HIDES_STRUCT = @DOXYGEN_TYPEDEF_HIDES_STRUCT@ +LOOKUP_CACHE_SIZE = @DOXYGEN_LOOKUP_CACHE_SIZE@ +NUM_PROC_THREADS = @DOXYGEN_NUM_PROC_THREADS@ +TIMESTAMP = @DOXYGEN_TIMESTAMP@ +EXTRACT_ALL = @DOXYGEN_EXTRACT_ALL@ +EXTRACT_PRIVATE = @DOXYGEN_EXTRACT_PRIVATE@ +EXTRACT_PRIV_VIRTUAL = @DOXYGEN_EXTRACT_PRIV_VIRTUAL@ +EXTRACT_PACKAGE = @DOXYGEN_EXTRACT_PACKAGE@ +EXTRACT_STATIC = @DOXYGEN_EXTRACT_STATIC@ +EXTRACT_LOCAL_CLASSES = @DOXYGEN_EXTRACT_LOCAL_CLASSES@ +EXTRACT_LOCAL_METHODS = @DOXYGEN_EXTRACT_LOCAL_METHODS@ +EXTRACT_ANON_NSPACES = @DOXYGEN_EXTRACT_ANON_NSPACES@ +RESOLVE_UNNAMED_PARAMS = @DOXYGEN_RESOLVE_UNNAMED_PARAMS@ +HIDE_UNDOC_MEMBERS = @DOXYGEN_HIDE_UNDOC_MEMBERS@ +HIDE_UNDOC_CLASSES = @DOXYGEN_HIDE_UNDOC_CLASSES@ +HIDE_FRIEND_COMPOUNDS = @DOXYGEN_HIDE_FRIEND_COMPOUNDS@ +HIDE_IN_BODY_DOCS = @DOXYGEN_HIDE_IN_BODY_DOCS@ +INTERNAL_DOCS = @DOXYGEN_INTERNAL_DOCS@ +CASE_SENSE_NAMES = @DOXYGEN_CASE_SENSE_NAMES@ +HIDE_SCOPE_NAMES = @DOXYGEN_HIDE_SCOPE_NAMES@ +HIDE_COMPOUND_REFERENCE= @DOXYGEN_HIDE_COMPOUND_REFERENCE@ +SHOW_HEADERFILE = @DOXYGEN_SHOW_HEADERFILE@ +SHOW_INCLUDE_FILES = @DOXYGEN_SHOW_INCLUDE_FILES@ +SHOW_GROUPED_MEMB_INC = @DOXYGEN_SHOW_GROUPED_MEMB_INC@ +FORCE_LOCAL_INCLUDES = @DOXYGEN_FORCE_LOCAL_INCLUDES@ +INLINE_INFO = @DOXYGEN_INLINE_INFO@ +SORT_MEMBER_DOCS = @DOXYGEN_SORT_MEMBER_DOCS@ +SORT_BRIEF_DOCS = @DOXYGEN_SORT_BRIEF_DOCS@ +SORT_MEMBERS_CTORS_1ST = @DOXYGEN_SORT_MEMBERS_CTORS_1ST@ +SORT_GROUP_NAMES = @DOXYGEN_SORT_GROUP_NAMES@ +SORT_BY_SCOPE_NAME = @DOXYGEN_SORT_BY_SCOPE_NAME@ +STRICT_PROTO_MATCHING = @DOXYGEN_STRICT_PROTO_MATCHING@ +GENERATE_TODOLIST = @DOXYGEN_GENERATE_TODOLIST@ +GENERATE_TESTLIST = @DOXYGEN_GENERATE_TESTLIST@ +GENERATE_BUGLIST = @DOXYGEN_GENERATE_BUGLIST@ +GENERATE_DEPRECATEDLIST= @DOXYGEN_GENERATE_DEPRECATEDLIST@ +ENABLED_SECTIONS = @DOXYGEN_ENABLED_SECTIONS@ +MAX_INITIALIZER_LINES = @DOXYGEN_MAX_INITIALIZER_LINES@ +SHOW_USED_FILES = @DOXYGEN_SHOW_USED_FILES@ +SHOW_FILES = @DOXYGEN_SHOW_FILES@ +SHOW_NAMESPACES = @DOXYGEN_SHOW_NAMESPACES@ +FILE_VERSION_FILTER = @DOXYGEN_FILE_VERSION_FILTER@ +LAYOUT_FILE = @DOXYGEN_LAYOUT_FILE@ +CITE_BIB_FILES = @DOXYGEN_CITE_BIB_FILES@ +QUIET = @DOXYGEN_QUIET@ +WARNINGS = @DOXYGEN_WARNINGS@ +WARN_IF_UNDOCUMENTED = @DOXYGEN_WARN_IF_UNDOCUMENTED@ +WARN_IF_DOC_ERROR = @DOXYGEN_WARN_IF_DOC_ERROR@ +WARN_IF_INCOMPLETE_DOC = @DOXYGEN_WARN_IF_INCOMPLETE_DOC@ +WARN_NO_PARAMDOC = @DOXYGEN_WARN_NO_PARAMDOC@ +WARN_IF_UNDOC_ENUM_VAL = @DOXYGEN_WARN_IF_UNDOC_ENUM_VAL@ +WARN_AS_ERROR = @DOXYGEN_WARN_AS_ERROR@ +WARN_FORMAT = @DOXYGEN_WARN_FORMAT@ +WARN_LINE_FORMAT = @DOXYGEN_WARN_LINE_FORMAT@ +WARN_LOGFILE = @DOXYGEN_WARN_LOGFILE@ +INPUT = @DOXYGEN_INPUT@ +INPUT_ENCODING = @DOXYGEN_INPUT_ENCODING@ +INPUT_FILE_ENCODING = @DOXYGEN_INPUT_FILE_ENCODING@ +FILE_PATTERNS = @DOXYGEN_FILE_PATTERNS@ +RECURSIVE = @DOXYGEN_RECURSIVE@ +EXCLUDE = @DOXYGEN_EXCLUDE@ +EXCLUDE_SYMLINKS = @DOXYGEN_EXCLUDE_SYMLINKS@ +EXCLUDE_PATTERNS = @DOXYGEN_EXCLUDE_PATTERNS@ +EXCLUDE_SYMBOLS = @DOXYGEN_EXCLUDE_SYMBOLS@ +EXAMPLE_PATH = @DOXYGEN_EXAMPLE_PATH@ +EXAMPLE_PATTERNS = @DOXYGEN_EXAMPLE_PATTERNS@ +EXAMPLE_RECURSIVE = @DOXYGEN_EXAMPLE_RECURSIVE@ +IMAGE_PATH = @DOXYGEN_IMAGE_PATH@ +INPUT_FILTER = @DOXYGEN_INPUT_FILTER@ +FILTER_PATTERNS = @DOXYGEN_FILTER_PATTERNS@ +FILTER_SOURCE_FILES = @DOXYGEN_FILTER_SOURCE_FILES@ +FILTER_SOURCE_PATTERNS = @DOXYGEN_FILTER_SOURCE_PATTERNS@ +USE_MDFILE_AS_MAINPAGE = @DOXYGEN_USE_MDFILE_AS_MAINPAGE@ +FORTRAN_COMMENT_AFTER = @DOXYGEN_FORTRAN_COMMENT_AFTER@ +SOURCE_BROWSER = @DOXYGEN_SOURCE_BROWSER@ +INLINE_SOURCES = @DOXYGEN_INLINE_SOURCES@ +STRIP_CODE_COMMENTS = @DOXYGEN_STRIP_CODE_COMMENTS@ +REFERENCED_BY_RELATION = @DOXYGEN_REFERENCED_BY_RELATION@ +REFERENCES_RELATION = @DOXYGEN_REFERENCES_RELATION@ +REFERENCES_LINK_SOURCE = @DOXYGEN_REFERENCES_LINK_SOURCE@ +SOURCE_TOOLTIPS = @DOXYGEN_SOURCE_TOOLTIPS@ +USE_HTAGS = @DOXYGEN_USE_HTAGS@ +VERBATIM_HEADERS = @DOXYGEN_VERBATIM_HEADERS@ +CLANG_ASSISTED_PARSING = @DOXYGEN_CLANG_ASSISTED_PARSING@ +CLANG_ADD_INC_PATHS = @DOXYGEN_CLANG_ADD_INC_PATHS@ +CLANG_OPTIONS = @DOXYGEN_CLANG_OPTIONS@ +CLANG_DATABASE_PATH = @DOXYGEN_CLANG_DATABASE_PATH@ +ALPHABETICAL_INDEX = @DOXYGEN_ALPHABETICAL_INDEX@ +IGNORE_PREFIX = @DOXYGEN_IGNORE_PREFIX@ +GENERATE_HTML = @DOXYGEN_GENERATE_HTML@ +HTML_OUTPUT = @DOXYGEN_HTML_OUTPUT@ +HTML_FILE_EXTENSION = @DOXYGEN_HTML_FILE_EXTENSION@ +HTML_HEADER = @DOXYGEN_HTML_HEADER@ +HTML_FOOTER = @DOXYGEN_HTML_FOOTER@ +HTML_STYLESHEET = @DOXYGEN_HTML_STYLESHEET@ +HTML_EXTRA_STYLESHEET = @DOXYGEN_HTML_EXTRA_STYLESHEET@ +HTML_EXTRA_FILES = @DOXYGEN_HTML_EXTRA_FILES@ +HTML_COLORSTYLE = @DOXYGEN_HTML_COLORSTYLE@ +HTML_COLORSTYLE_HUE = @DOXYGEN_HTML_COLORSTYLE_HUE@ +HTML_COLORSTYLE_SAT = @DOXYGEN_HTML_COLORSTYLE_SAT@ +HTML_COLORSTYLE_GAMMA = @DOXYGEN_HTML_COLORSTYLE_GAMMA@ +HTML_DYNAMIC_MENUS = @DOXYGEN_HTML_DYNAMIC_MENUS@ +HTML_DYNAMIC_SECTIONS = @DOXYGEN_HTML_DYNAMIC_SECTIONS@ +HTML_CODE_FOLDING = @DOXYGEN_HTML_CODE_FOLDING@ +HTML_INDEX_NUM_ENTRIES = @DOXYGEN_HTML_INDEX_NUM_ENTRIES@ +GENERATE_DOCSET = @DOXYGEN_GENERATE_DOCSET@ +DOCSET_FEEDNAME = @DOXYGEN_DOCSET_FEEDNAME@ +DOCSET_FEEDURL = @DOXYGEN_DOCSET_FEEDURL@ +DOCSET_BUNDLE_ID = @DOXYGEN_DOCSET_BUNDLE_ID@ +DOCSET_PUBLISHER_ID = @DOXYGEN_DOCSET_PUBLISHER_ID@ +DOCSET_PUBLISHER_NAME = @DOXYGEN_DOCSET_PUBLISHER_NAME@ +GENERATE_HTMLHELP = @DOXYGEN_GENERATE_HTMLHELP@ +CHM_FILE = @DOXYGEN_CHM_FILE@ +HHC_LOCATION = @DOXYGEN_HHC_LOCATION@ +GENERATE_CHI = @DOXYGEN_GENERATE_CHI@ +CHM_INDEX_ENCODING = @DOXYGEN_CHM_INDEX_ENCODING@ +BINARY_TOC = @DOXYGEN_BINARY_TOC@ +TOC_EXPAND = @DOXYGEN_TOC_EXPAND@ +SITEMAP_URL = @DOXYGEN_SITEMAP_URL@ +GENERATE_QHP = @DOXYGEN_GENERATE_QHP@ +QCH_FILE = @DOXYGEN_QCH_FILE@ +QHP_NAMESPACE = @DOXYGEN_QHP_NAMESPACE@ +QHP_VIRTUAL_FOLDER = @DOXYGEN_QHP_VIRTUAL_FOLDER@ +QHP_CUST_FILTER_NAME = @DOXYGEN_QHP_CUST_FILTER_NAME@ +QHP_CUST_FILTER_ATTRS = @DOXYGEN_QHP_CUST_FILTER_ATTRS@ +QHP_SECT_FILTER_ATTRS = @DOXYGEN_QHP_SECT_FILTER_ATTRS@ +QHG_LOCATION = @DOXYGEN_QHG_LOCATION@ +GENERATE_ECLIPSEHELP = @DOXYGEN_GENERATE_ECLIPSEHELP@ +ECLIPSE_DOC_ID = @DOXYGEN_ECLIPSE_DOC_ID@ +DISABLE_INDEX = @DOXYGEN_DISABLE_INDEX@ +GENERATE_TREEVIEW = @DOXYGEN_GENERATE_TREEVIEW@ +FULL_SIDEBAR = @DOXYGEN_FULL_SIDEBAR@ +ENUM_VALUES_PER_LINE = @DOXYGEN_ENUM_VALUES_PER_LINE@ +TREEVIEW_WIDTH = @DOXYGEN_TREEVIEW_WIDTH@ +EXT_LINKS_IN_WINDOW = @DOXYGEN_EXT_LINKS_IN_WINDOW@ +OBFUSCATE_EMAILS = @DOXYGEN_OBFUSCATE_EMAILS@ +HTML_FORMULA_FORMAT = @DOXYGEN_HTML_FORMULA_FORMAT@ +FORMULA_FONTSIZE = @DOXYGEN_FORMULA_FONTSIZE@ +FORMULA_MACROFILE = @DOXYGEN_FORMULA_MACROFILE@ +USE_MATHJAX = @DOXYGEN_USE_MATHJAX@ +MATHJAX_VERSION = @DOXYGEN_MATHJAX_VERSION@ +MATHJAX_FORMAT = @DOXYGEN_MATHJAX_FORMAT@ +MATHJAX_RELPATH = @DOXYGEN_MATHJAX_RELPATH@ +MATHJAX_EXTENSIONS = @DOXYGEN_MATHJAX_EXTENSIONS@ +MATHJAX_CODEFILE = @DOXYGEN_MATHJAX_CODEFILE@ +SEARCHENGINE = @DOXYGEN_SEARCHENGINE@ +SERVER_BASED_SEARCH = @DOXYGEN_SERVER_BASED_SEARCH@ +EXTERNAL_SEARCH = @DOXYGEN_EXTERNAL_SEARCH@ +SEARCHENGINE_URL = @DOXYGEN_SEARCHENGINE_URL@ +SEARCHDATA_FILE = @DOXYGEN_SEARCHDATA_FILE@ +EXTERNAL_SEARCH_ID = @DOXYGEN_EXTERNAL_SEARCH_ID@ +EXTRA_SEARCH_MAPPINGS = @DOXYGEN_EXTRA_SEARCH_MAPPINGS@ +GENERATE_LATEX = @DOXYGEN_GENERATE_LATEX@ +LATEX_OUTPUT = @DOXYGEN_LATEX_OUTPUT@ +LATEX_CMD_NAME = @DOXYGEN_LATEX_CMD_NAME@ +MAKEINDEX_CMD_NAME = @DOXYGEN_MAKEINDEX_CMD_NAME@ +LATEX_MAKEINDEX_CMD = @DOXYGEN_LATEX_MAKEINDEX_CMD@ +COMPACT_LATEX = @DOXYGEN_COMPACT_LATEX@ +PAPER_TYPE = @DOXYGEN_PAPER_TYPE@ +EXTRA_PACKAGES = @DOXYGEN_EXTRA_PACKAGES@ +LATEX_HEADER = @DOXYGEN_LATEX_HEADER@ +LATEX_FOOTER = @DOXYGEN_LATEX_FOOTER@ +LATEX_EXTRA_STYLESHEET = @DOXYGEN_LATEX_EXTRA_STYLESHEET@ +LATEX_EXTRA_FILES = @DOXYGEN_LATEX_EXTRA_FILES@ +PDF_HYPERLINKS = @DOXYGEN_PDF_HYPERLINKS@ +USE_PDFLATEX = @DOXYGEN_USE_PDFLATEX@ +LATEX_BATCHMODE = @DOXYGEN_LATEX_BATCHMODE@ +LATEX_HIDE_INDICES = @DOXYGEN_LATEX_HIDE_INDICES@ +LATEX_BIB_STYLE = @DOXYGEN_LATEX_BIB_STYLE@ +LATEX_EMOJI_DIRECTORY = @DOXYGEN_LATEX_EMOJI_DIRECTORY@ +GENERATE_RTF = @DOXYGEN_GENERATE_RTF@ +RTF_OUTPUT = @DOXYGEN_RTF_OUTPUT@ +COMPACT_RTF = @DOXYGEN_COMPACT_RTF@ +RTF_HYPERLINKS = @DOXYGEN_RTF_HYPERLINKS@ +RTF_STYLESHEET_FILE = @DOXYGEN_RTF_STYLESHEET_FILE@ +RTF_EXTENSIONS_FILE = @DOXYGEN_RTF_EXTENSIONS_FILE@ +GENERATE_MAN = @DOXYGEN_GENERATE_MAN@ +MAN_OUTPUT = @DOXYGEN_MAN_OUTPUT@ +MAN_EXTENSION = @DOXYGEN_MAN_EXTENSION@ +MAN_SUBDIR = @DOXYGEN_MAN_SUBDIR@ +MAN_LINKS = @DOXYGEN_MAN_LINKS@ +GENERATE_XML = @DOXYGEN_GENERATE_XML@ +XML_OUTPUT = @DOXYGEN_XML_OUTPUT@ +XML_PROGRAMLISTING = @DOXYGEN_XML_PROGRAMLISTING@ +XML_NS_MEMB_FILE_SCOPE = @DOXYGEN_XML_NS_MEMB_FILE_SCOPE@ +GENERATE_DOCBOOK = @DOXYGEN_GENERATE_DOCBOOK@ +DOCBOOK_OUTPUT = @DOXYGEN_DOCBOOK_OUTPUT@ +GENERATE_AUTOGEN_DEF = @DOXYGEN_GENERATE_AUTOGEN_DEF@ +GENERATE_SQLITE3 = @DOXYGEN_GENERATE_SQLITE3@ +SQLITE3_OUTPUT = @DOXYGEN_SQLITE3_OUTPUT@ +SQLITE3_RECREATE_DB = @DOXYGEN_SQLITE3_RECREATE_DB@ +GENERATE_PERLMOD = @DOXYGEN_GENERATE_PERLMOD@ +PERLMOD_LATEX = @DOXYGEN_PERLMOD_LATEX@ +PERLMOD_PRETTY = @DOXYGEN_PERLMOD_PRETTY@ +PERLMOD_MAKEVAR_PREFIX = @DOXYGEN_PERLMOD_MAKEVAR_PREFIX@ +ENABLE_PREPROCESSING = @DOXYGEN_ENABLE_PREPROCESSING@ +MACRO_EXPANSION = @DOXYGEN_MACRO_EXPANSION@ +EXPAND_ONLY_PREDEF = @DOXYGEN_EXPAND_ONLY_PREDEF@ +SEARCH_INCLUDES = @DOXYGEN_SEARCH_INCLUDES@ +INCLUDE_PATH = @DOXYGEN_INCLUDE_PATH@ +INCLUDE_FILE_PATTERNS = @DOXYGEN_INCLUDE_FILE_PATTERNS@ +PREDEFINED = @DOXYGEN_PREDEFINED@ +EXPAND_AS_DEFINED = @DOXYGEN_EXPAND_AS_DEFINED@ +SKIP_FUNCTION_MACROS = @DOXYGEN_SKIP_FUNCTION_MACROS@ +TAGFILES = @DOXYGEN_TAGFILES@ +GENERATE_TAGFILE = @DOXYGEN_GENERATE_TAGFILE@ +ALLEXTERNALS = @DOXYGEN_ALLEXTERNALS@ +EXTERNAL_GROUPS = @DOXYGEN_EXTERNAL_GROUPS@ +EXTERNAL_PAGES = @DOXYGEN_EXTERNAL_PAGES@ +HIDE_UNDOC_RELATIONS = @DOXYGEN_HIDE_UNDOC_RELATIONS@ +HAVE_DOT = @DOXYGEN_HAVE_DOT@ +DOT_NUM_THREADS = @DOXYGEN_DOT_NUM_THREADS@ +DOT_COMMON_ATTR = @DOXYGEN_DOT_COMMON_ATTR@ +DOT_EDGE_ATTR = @DOXYGEN_DOT_EDGE_ATTR@ +DOT_NODE_ATTR = @DOXYGEN_DOT_NODE_ATTR@ +DOT_FONTPATH = @DOXYGEN_DOT_FONTPATH@ +CLASS_GRAPH = @DOXYGEN_CLASS_GRAPH@ +COLLABORATION_GRAPH = @DOXYGEN_COLLABORATION_GRAPH@ +GROUP_GRAPHS = @DOXYGEN_GROUP_GRAPHS@ +UML_LOOK = @DOXYGEN_UML_LOOK@ +UML_LIMIT_NUM_FIELDS = @DOXYGEN_UML_LIMIT_NUM_FIELDS@ +DOT_UML_DETAILS = @DOXYGEN_DOT_UML_DETAILS@ +DOT_WRAP_THRESHOLD = @DOXYGEN_DOT_WRAP_THRESHOLD@ +TEMPLATE_RELATIONS = @DOXYGEN_TEMPLATE_RELATIONS@ +INCLUDE_GRAPH = @DOXYGEN_INCLUDE_GRAPH@ +INCLUDED_BY_GRAPH = @DOXYGEN_INCLUDED_BY_GRAPH@ +CALL_GRAPH = @DOXYGEN_CALL_GRAPH@ +CALLER_GRAPH = @DOXYGEN_CALLER_GRAPH@ +GRAPHICAL_HIERARCHY = @DOXYGEN_GRAPHICAL_HIERARCHY@ +DIRECTORY_GRAPH = @DOXYGEN_DIRECTORY_GRAPH@ +DIR_GRAPH_MAX_DEPTH = @DOXYGEN_DIR_GRAPH_MAX_DEPTH@ +DOT_IMAGE_FORMAT = @DOXYGEN_DOT_IMAGE_FORMAT@ +INTERACTIVE_SVG = @DOXYGEN_INTERACTIVE_SVG@ +DOT_PATH = @DOXYGEN_DOT_PATH@ +DOTFILE_DIRS = @DOXYGEN_DOTFILE_DIRS@ +DIA_PATH = @DOXYGEN_DIA_PATH@ +DIAFILE_DIRS = @DOXYGEN_DIAFILE_DIRS@ +PLANTUML_JAR_PATH = @DOXYGEN_PLANTUML_JAR_PATH@ +PLANTUML_CFG_FILE = @DOXYGEN_PLANTUML_CFG_FILE@ +PLANTUML_INCLUDE_PATH = @DOXYGEN_PLANTUML_INCLUDE_PATH@ +DOT_GRAPH_MAX_NODES = @DOXYGEN_DOT_GRAPH_MAX_NODES@ +MAX_DOT_GRAPH_DEPTH = @DOXYGEN_MAX_DOT_GRAPH_DEPTH@ +DOT_MULTI_TARGETS = @DOXYGEN_DOT_MULTI_TARGETS@ +GENERATE_LEGEND = @DOXYGEN_GENERATE_LEGEND@ +DOT_CLEANUP = @DOXYGEN_DOT_CLEANUP@ +MSCGEN_TOOL = @DOXYGEN_MSCGEN_TOOL@ +MSCFILE_DIRS = @DOXYGEN_MSCFILE_DIRS@ diff --git a/build-coverage/Doxyfile.qtty_cpp b/build-coverage/Doxyfile.qtty_cpp new file mode 100644 index 0000000..beddd9e --- /dev/null +++ b/build-coverage/Doxyfile.qtty_cpp @@ -0,0 +1,65 @@ +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = "qtty-cpp" +PROJECT_NUMBER = "0.1.0" +PROJECT_BRIEF = "Header-only C++ wrapper for qtty" +PROJECT_LOGO = "/home/valles/workspace/siderust/siderust-cpp/qtty-cpp/../../public/logo.png" +OUTPUT_DIRECTORY = "/home/valles/workspace/siderust/siderust-cpp/qtty-cpp/build-coverage/docs/doxygen" +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ALWAYS_DETAILED_SEC = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = "/home/valles/workspace/siderust/siderust-cpp/qtty-cpp" +STRIP_FROM_INC_PATH = "/home/valles/workspace/siderust/siderust-cpp/qtty-cpp/include" + +MARKDOWN_SUPPORT = YES +AUTOLINK_SUPPORT = YES +BUILTIN_STL_SUPPORT = YES + +EXTRACT_ALL = YES +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +INTERNAL_DOCS = NO + +QUIET = YES +WARNINGS = YES +WARN_IF_UNDOCUMENTED = NO +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_AS_ERROR = NO + +INPUT = \ + "/home/valles/workspace/siderust/siderust-cpp/qtty-cpp/docs" \ + "/home/valles/workspace/siderust/siderust-cpp/qtty-cpp/docs/mainpage.md" \ + "/home/valles/workspace/siderust/siderust-cpp/qtty-cpp/docs/README.md" \ + "/home/valles/workspace/siderust/siderust-cpp/qtty-cpp/include/qtty" +FILE_PATTERNS = *.hpp *.md +RECURSIVE = YES +EXAMPLE_PATH = "/home/valles/workspace/siderust/siderust-cpp/qtty-cpp/examples" +EXAMPLE_PATTERNS = *.cpp +USE_MDFILE_AS_MAINPAGE = "/home/valles/workspace/siderust/siderust-cpp/qtty-cpp/docs/mainpage.md" + +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +SKIP_FUNCTION_MACROS = YES +INCLUDE_PATH = \ + "/home/valles/workspace/siderust/siderust-cpp/qtty-cpp/include" \ + "/home/valles/workspace/siderust/siderust-cpp/qtty-cpp/qtty/qtty-ffi/include" + +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +VERBATIM_HEADERS = YES + +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_DYNAMIC_MENUS = YES +GENERATE_TREEVIEW = YES +TOC_INCLUDE_HEADINGS = 2 + +GENERATE_LATEX = NO +GENERATE_XML = NO diff --git a/gen_cpp_units/src/main.rs b/gen_cpp_units/src/main.rs index 520c951..9a3f689 100644 --- a/gen_cpp_units/src/main.rs +++ b/gen_cpp_units/src/main.rs @@ -138,10 +138,10 @@ fn parse_csv(path: &Path) -> Vec { continue; } - // Split on (at most) 5 commas to protect ratio values that may - // themselves contain commas (defensive, though none currently do). - let parts: Vec<&str> = line.splitn(5, ',').collect(); - if parts.len() != 5 { + // Split on commas — we need at least 5 fields, but allow extra + // (e.g. an optional 6th field for Rust type path used by qtty-ffi). + let parts: Vec<&str> = line.splitn(6, ',').collect(); + if parts.len() < 5 { eprintln!("Warning: skipping malformed line: {line}"); continue; } diff --git a/include/qtty/ffi_core.hpp b/include/qtty/ffi_core.hpp index 51408b4..c25daaa 100644 --- a/include/qtty/ffi_core.hpp +++ b/include/qtty/ffi_core.hpp @@ -102,11 +102,22 @@ inline void check_status(int32_t status, const char *operation) { // Forward declarations template class Quantity; +template struct CompoundTag; + +// Type trait to detect compound (derived) unit tags +template struct is_compound : std::false_type {}; +template +struct is_compound> : std::true_type {}; +template +inline constexpr bool is_compound_v = is_compound::value; // Template trait to get unit ID from unit tag // Each unit tag (e.g., MeterTag) must specialize this template to provide // its corresponding C FFI unit ID constant (e.g., UNIT_ID_METER). // Specializations are auto-generated in include/qtty/units/*.hpp +// +// For compound tags, specializations provide numerator_unit_id() and +// denominator_unit_id() instead of a single unit_id(). template struct UnitTraits { // Default symbol returns empty string. Specialize for units that have // symbols. @@ -172,17 +183,39 @@ template class Quantity { template Quantity::type> to() const { using TargetTag = typename ExtractTag::type; - qtty_quantity_t src_qty; - qtty_quantity_t dst_qty; - - int32_t status = qtty_quantity_make(m_value, unit_id(), &src_qty); - check_status(status, "Creating source quantity"); - - status = qtty_quantity_convert(src_qty, UnitTraits::unit_id(), - &dst_qty); - check_status(status, "Converting units"); - return Quantity(dst_qty.value); + if constexpr (is_compound_v) { + // Compound → compound conversion via qtty_derived_convert + static_assert(is_compound_v, + "Cannot convert compound unit to simple unit"); + qtty_derived_quantity_t src_qty; + qtty_derived_quantity_t dst_qty; + + int32_t status = qtty_derived_make( + m_value, UnitTraits::numerator_unit_id(), + UnitTraits::denominator_unit_id(), &src_qty); + check_status(status, "Creating derived source quantity"); + + status = qtty_derived_convert( + src_qty, UnitTraits::numerator_unit_id(), + UnitTraits::denominator_unit_id(), &dst_qty); + check_status(status, "Converting derived units"); + + return Quantity(dst_qty.value); + } else { + // Simple unit conversion via qtty_quantity_convert + qtty_quantity_t src_qty; + qtty_quantity_t dst_qty; + + int32_t status = qtty_quantity_make(m_value, unit_id(), &src_qty); + check_status(status, "Creating source quantity"); + + status = qtty_quantity_convert(src_qty, UnitTraits::unit_id(), + &dst_qty); + check_status(status, "Converting units"); + + return Quantity(dst_qty.value); + } } // ======================================================================== diff --git a/include/qtty/literals.hpp b/include/qtty/literals.hpp index de3dbb4..b360c2f 100644 --- a/include/qtty/literals.hpp +++ b/include/qtty/literals.hpp @@ -3,11 +3,11 @@ #pragma once -#include "units/angular.hpp" #include "units/length.hpp" +#include "units/time.hpp" +#include "units/angular.hpp" #include "units/mass.hpp" #include "units/power.hpp" -#include "units/time.hpp" namespace qtty { @@ -189,8 +189,7 @@ constexpr ClassicalElectronRadius operator""_r_e(unsigned long long value) { constexpr ElectronReducedComptonWavelength operator""__e(long double value) { return ElectronReducedComptonWavelength(static_cast(value)); } -constexpr ElectronReducedComptonWavelength -operator""__e(unsigned long long value) { +constexpr ElectronReducedComptonWavelength operator""__e(unsigned long long value) { return ElectronReducedComptonWavelength(static_cast(value)); } @@ -316,8 +315,7 @@ constexpr NominalLunarDistance operator""_LD(unsigned long long value) { constexpr NominalEarthPolarRadius operator""_R_earthpol(long double value) { return NominalEarthPolarRadius(static_cast(value)); } -constexpr NominalEarthPolarRadius -operator""_R_earthpol(unsigned long long value) { +constexpr NominalEarthPolarRadius operator""_R_earthpol(unsigned long long value) { return NominalEarthPolarRadius(static_cast(value)); } @@ -331,24 +329,21 @@ constexpr NominalEarthRadius operator""_R_earth(unsigned long long value) { constexpr NominalEarthEquatorialRadius operator""_R_eartheq(long double value) { return NominalEarthEquatorialRadius(static_cast(value)); } -constexpr NominalEarthEquatorialRadius -operator""_R_eartheq(unsigned long long value) { +constexpr NominalEarthEquatorialRadius operator""_R_eartheq(unsigned long long value) { return NominalEarthEquatorialRadius(static_cast(value)); } constexpr EarthMeridionalCircumference operator""_C_mer(long double value) { return EarthMeridionalCircumference(static_cast(value)); } -constexpr EarthMeridionalCircumference -operator""_C_mer(unsigned long long value) { +constexpr EarthMeridionalCircumference operator""_C_mer(unsigned long long value) { return EarthMeridionalCircumference(static_cast(value)); } constexpr EarthEquatorialCircumference operator""_C_eq(long double value) { return EarthEquatorialCircumference(static_cast(value)); } -constexpr EarthEquatorialCircumference -operator""_C_eq(unsigned long long value) { +constexpr EarthEquatorialCircumference operator""_C_eq(unsigned long long value) { return EarthEquatorialCircumference(static_cast(value)); } diff --git a/include/qtty/serialization.hpp b/include/qtty/serialization.hpp index 4a77ef9..a6270c5 100644 --- a/include/qtty/serialization.hpp +++ b/include/qtty/serialization.hpp @@ -26,6 +26,8 @@ int32_t qtty_quantity_from_json_value(UnitId unit, const char *json, qtty_quantity_t *out); int32_t qtty_quantity_to_json(qtty_quantity_t src, char **out_json); int32_t qtty_quantity_from_json(const char *json, qtty_quantity_t *out); +int32_t qtty_derived_to_json(qtty_derived_quantity_t src, char **out); +int32_t qtty_derived_from_json(const char *json, qtty_derived_quantity_t *out); void qtty_string_free(char *s); } @@ -140,4 +142,63 @@ Quantity::type> from_json(std::string_view json) { } } // namespace serialization + +// ============================================================================ +// Compound Quantity Serialization +// ============================================================================ +// Serialize/deserialize derived quantities (e.g., velocity) via the Rust FFI. + +namespace derived_serialization { + +/** + * @brief Serialize a compound quantity as JSON. + * @tparam Tag CompoundTag type of the quantity. + * @param q Source compound quantity. + * @return JSON string. + */ +template +std::string to_json(const Quantity &q) { + static_assert(is_compound_v, + "derived_serialization::to_json requires a compound quantity"); + qtty_derived_quantity_t src{}; + int32_t status = qtty_derived_make( + q.value(), UnitTraits::numerator_unit_id(), + UnitTraits::denominator_unit_id(), &src); + check_status(status, "Creating derived quantity for serialization"); + + char *out = nullptr; + status = qtty_derived_to_json(src, &out); + check_status(status, "Serializing derived quantity to JSON"); + return serialization::from_owned_c(out); +} + +/** + * @brief Deserialize a JSON string into a compound quantity. + * @tparam T CompoundTag or Quantity type. + * @param json JSON input string view. + * @return Deserialized compound quantity, converted to requested target units. + */ +template +Quantity::type> from_json(std::string_view json) { + using Tag = typename ExtractTag::type; + static_assert(is_compound_v, + "derived_serialization::from_json requires a compound type"); + qtty_derived_quantity_t out_qty{}; + int32_t status = qtty_derived_from_json(json.data(), &out_qty); + check_status(status, "Deserializing derived quantity from JSON"); + + // Convert to requested units if needed + if (out_qty.numerator != UnitTraits::numerator_unit_id() || + out_qty.denominator != UnitTraits::denominator_unit_id()) { + qtty_derived_quantity_t conv{}; + status = qtty_derived_convert( + out_qty, UnitTraits::numerator_unit_id(), + UnitTraits::denominator_unit_id(), &conv); + check_status(status, "Converting deserialized derived quantity"); + return Quantity(conv.value); + } + return Quantity(out_qty.value); +} + +} // namespace derived_serialization } // namespace qtty diff --git a/include/qtty/units/length.hpp b/include/qtty/units/length.hpp index f0c629a..67efda6 100644 --- a/include/qtty/units/length.hpp +++ b/include/qtty/units/length.hpp @@ -151,15 +151,11 @@ template <> struct UnitTraits { static constexpr std::string_view symbol() { return "a₀"; } }; template <> struct UnitTraits { - static constexpr UnitId unit_id() { - return UNIT_ID_CLASSICAL_ELECTRON_RADIUS; - } + 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 UnitId unit_id() { return UNIT_ID_ELECTRON_REDUCED_COMPTON_WAVELENGTH; } static constexpr std::string_view symbol() { return "λ̄_e"; } }; template <> struct UnitTraits { @@ -231,9 +227,7 @@ template <> struct UnitTraits { 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 UnitId unit_id() { return UNIT_ID_NOMINAL_EARTH_POLAR_RADIUS; } static constexpr std::string_view symbol() { return "R_⊕pol"; } }; template <> struct UnitTraits { @@ -241,21 +235,15 @@ template <> struct UnitTraits { 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 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 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 UnitId unit_id() { return UNIT_ID_EARTH_EQUATORIAL_CIRCUMFERENCE; } static constexpr std::string_view symbol() { return "C_eq"; } }; template <> struct UnitTraits { @@ -295,8 +283,7 @@ using Zettameter = Quantity; using Yottameter = Quantity; using BohrRadius = Quantity; using ClassicalElectronRadius = Quantity; -using ElectronReducedComptonWavelength = - Quantity; +using ElectronReducedComptonWavelength = Quantity; using AstronomicalUnit = Quantity; using LightYear = Quantity; using Parsec = Quantity; diff --git a/include/qtty/units/velocity.hpp b/include/qtty/units/velocity.hpp index c4077ba..88540ca 100644 --- a/include/qtty/units/velocity.hpp +++ b/include/qtty/units/velocity.hpp @@ -13,20 +13,16 @@ namespace qtty { // Compound Units: Velocity // ============================================================================ // Velocity is a derived quantity representing length divided by time. -// Unlike base dimensions (length, time, mass, etc.), compound units are not -// directly supported by the C FFI layer. Instead, we use C++ template -// metaprogramming to encode the compound relationship in the type system. +// Compound units are fully supported through the FFI layer via +// qtty_derived_make() and qtty_derived_convert(), which independently convert +// numerator and denominator units to produce the correct result. // // Design: CompoundTag encodes a quotient of -// two unit types. The division operator (/) creates instances by dividing -// the raw values, while the type system tracks the unit relationship. +// two unit types. The type system tracks the unit relationship at compile +// time, while the Rust FFI layer handles conversions at runtime. // -// Limitation: Conversions between different compound units (e.g., m/s to km/h) -// are not automatically supported. Users must manually convert numerator and -// denominator separately, then recombine. - -// Template for compound units (e.g., velocity = length/time) -template struct CompoundTag {}; +// Conversions between different compound units (e.g., m/s to km/h) are +// fully supported via the .to<>() method, just like simple unit conversions. // Velocity type alias using compound units // This is a template alias, not a concrete type. Instantiate with specific @@ -35,10 +31,6 @@ template using Velocity = Quantity< CompoundTag>; -// Note: The C API doesn't have explicit velocity unit IDs -// We create velocity by dividing length by time, operating on raw values -// No unit conversion is available for compound units through the C API - // ============================================================================ // Division Operator: Create Compound Units // ============================================================================ @@ -64,51 +56,56 @@ operator/(const Quantity &length, const Quantity &time) { // ============================================================================ // UnitTraits for Compound Units // ============================================================================ -// Provides symbols for common compound units. +// Compound tags expose numerator_unit_id() and denominator_unit_id() instead +// of a single unit_id(). The Quantity::to<>() template detects compound tags +// via is_compound_v<> and dispatches to qtty_derived_convert() accordingly. -// Generic template specialization for CompoundTag (requires units to have -// symbols) +// Generic template: derives unit IDs from the component tags 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 ""; + static constexpr UnitId numerator_unit_id() { + return UnitTraits::unit_id(); + } + static constexpr UnitId denominator_unit_id() { + return UnitTraits::unit_id(); } + static constexpr std::string_view symbol() { return ""; } }; -// Specializations for common velocity types +// Specializations for common velocity types: provide human-readable symbols template <> struct UnitTraits> { - static constexpr UnitId unit_id() { return UNIT_ID_METER; } + static constexpr UnitId numerator_unit_id() { return UNIT_ID_METER; } + static constexpr UnitId denominator_unit_id() { return UNIT_ID_SECOND; } static constexpr std::string_view symbol() { return "m/s"; } }; template <> struct UnitTraits> { - static constexpr UnitId unit_id() { return UNIT_ID_METER; } + static constexpr UnitId numerator_unit_id() { return UNIT_ID_KILOMETER; } + static constexpr UnitId denominator_unit_id() { return UNIT_ID_HOUR; } static constexpr std::string_view symbol() { return "km/h"; } }; template <> struct UnitTraits> { - static constexpr UnitId unit_id() { return UNIT_ID_METER; } + static constexpr UnitId numerator_unit_id() { return UNIT_ID_METER; } + static constexpr UnitId denominator_unit_id() { return UNIT_ID_HOUR; } static constexpr std::string_view symbol() { return "m/h"; } }; template <> struct UnitTraits> { - static constexpr UnitId unit_id() { return UNIT_ID_METER; } + static constexpr UnitId numerator_unit_id() { return UNIT_ID_KILOMETER; } + static constexpr UnitId denominator_unit_id() { return UNIT_ID_SECOND; } static constexpr std::string_view symbol() { return "km/s"; } }; template <> struct UnitTraits> { - static constexpr UnitId unit_id() { return UNIT_ID_METER; } + static constexpr UnitId numerator_unit_id() { return UNIT_ID_METER; } + static constexpr UnitId denominator_unit_id() { return UNIT_ID_MINUTE; } static constexpr std::string_view symbol() { return "m/min"; } }; template <> struct UnitTraits> { - static constexpr UnitId unit_id() { return UNIT_ID_METER; } + static constexpr UnitId numerator_unit_id() { return UNIT_ID_KILOMETER; } + static constexpr UnitId denominator_unit_id() { return UNIT_ID_MINUTE; } static constexpr std::string_view symbol() { return "km/min"; } }; @@ -119,8 +116,11 @@ template <> struct UnitTraits> { // These improve readability but are purely convenience types—they're just // specific instantiations of Quantity>. -// Common velocity type aliases (constructed from division, not convertible) using MeterPerSecond = Quantity>; using KilometerPerHour = Quantity>; +using KilometerPerSecond = Quantity>; +using MeterPerHour = Quantity>; +using MeterPerMinute = Quantity>; +using KilometerPerMinute = Quantity>; } // namespace qtty diff --git a/tests/test_derived.cpp b/tests/test_derived.cpp index ce8bb47..68c58ca 100644 --- a/tests/test_derived.cpp +++ b/tests/test_derived.cpp @@ -13,3 +13,48 @@ TEST_F(DerivedQuantityTest, VelocityCreation) { Velocity v1(10.0); EXPECT_EQ(v1.value(), 10.0); } + +TEST_F(DerivedQuantityTest, VelocityConversion) { + // 100 m/s should be 360 km/h + MeterPerSecond v_ms(100.0); + auto v_kmh = v_ms.to(); + EXPECT_NEAR(v_kmh.value(), 360.0, 1e-9); + + // Round-trip: 360 km/h → m/s + auto v_back = v_kmh.to(); + EXPECT_NEAR(v_back.value(), 100.0, 1e-9); +} + +TEST_F(DerivedQuantityTest, VelocityConversionKmToM) { + // 1 km/s should be 3600 km/h + KilometerPerSecond v_ks(1.0); + auto v_kmh = v_ks.to(); + EXPECT_NEAR(v_kmh.value(), 3600.0, 1e-9); +} + +TEST_F(DerivedQuantityTest, VelocityArithmetic) { + MeterPerSecond v1(10.0); + MeterPerSecond v2(5.0); + + auto sum = v1 + v2; + EXPECT_NEAR(sum.value(), 15.0, 1e-12); + + auto diff = v1 - v2; + EXPECT_NEAR(diff.value(), 5.0, 1e-12); + + auto scaled = v1 * 3.0; + EXPECT_NEAR(scaled.value(), 30.0, 1e-12); +} + +TEST_F(DerivedQuantityTest, VelocityFromDivision) { + // Create velocity from actual division + Kilometer dist(180.0); + Hour t(2.0); + auto v = dist / t; // type: KilometerPerHour + + EXPECT_NEAR(v.value(), 90.0, 1e-12); + + // Convert to m/s + auto v_ms = v.to(); + EXPECT_NEAR(v_ms.value(), 25.0, 1e-9); +} From 558c7d6b1ba61503a1147827d9258c4bff8e87ef Mon Sep 17 00:00:00 2001 From: VPRamon Date: Tue, 24 Feb 2026 19:06:49 +0100 Subject: [PATCH 08/10] fix: Remove unnecessary FFI features flag from CMake configuration in CI workflow --- .github/workflows/ci.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b44be2c..d38998f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,7 +55,7 @@ jobs: shell: bash run: | set -euo pipefail - cmake -S . -B build -G Ninja -DQTTY_BUILD_DOCS=OFF -DQTTY_FFI_FEATURES="serde" -DCMAKE_EXPORT_COMPILE_COMMANDS=ON + cmake -S . -B build -G Ninja -DQTTY_BUILD_DOCS=OFF -DCMAKE_EXPORT_COMPILE_COMMANDS=ON - name: clang-format check shell: bash @@ -156,7 +156,7 @@ jobs: shell: bash run: | set -euo pipefail - cmake -S . -B build -G Ninja -DQTTY_BUILD_DOCS=ON -DQTTY_FFI_FEATURES="serde" + cmake -S . -B build -G Ninja -DQTTY_BUILD_DOCS=ON - name: Build shell: bash @@ -214,7 +214,6 @@ jobs: set -euo pipefail cmake -S . -B build-coverage -G Ninja \ -DQTTY_BUILD_DOCS=OFF \ - -DQTTY_FFI_FEATURES="serde" \ -DCMAKE_BUILD_TYPE=Debug \ -DCMAKE_CXX_FLAGS="--coverage" \ -DCMAKE_EXE_LINKER_FLAGS="--coverage" From b0d36b07389ce1c572b2f3598069415f3e625c3d Mon Sep 17 00:00:00 2001 From: VPRamon Date: Tue, 24 Feb 2026 19:25:06 +0100 Subject: [PATCH 09/10] fix: Update subproject commit reference in qtty --- qtty | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qtty b/qtty index 1e26737..b2e0c39 160000 --- a/qtty +++ b/qtty @@ -1 +1 @@ -Subproject commit 1e26737cf20c2b4653726a0ad72502e8c98d65ea +Subproject commit b2e0c39b99ad097e22088860e322d018682952ed From 359214460a656adf052a25236cd38b8d95d3fc86 Mon Sep 17 00:00:00 2001 From: VPRamon Date: Tue, 24 Feb 2026 19:35:30 +0100 Subject: [PATCH 10/10] fix: apply clang-format to resolve CI formatting violations --- include/qtty/literals.hpp | 19 ++++++++++++------- include/qtty/serialization.hpp | 15 +++++++-------- include/qtty/units/length.hpp | 27 ++++++++++++++++++++------- tests/test_derived.cpp | 2 +- 4 files changed, 40 insertions(+), 23 deletions(-) diff --git a/include/qtty/literals.hpp b/include/qtty/literals.hpp index b360c2f..de3dbb4 100644 --- a/include/qtty/literals.hpp +++ b/include/qtty/literals.hpp @@ -3,11 +3,11 @@ #pragma once -#include "units/length.hpp" -#include "units/time.hpp" #include "units/angular.hpp" +#include "units/length.hpp" #include "units/mass.hpp" #include "units/power.hpp" +#include "units/time.hpp" namespace qtty { @@ -189,7 +189,8 @@ constexpr ClassicalElectronRadius operator""_r_e(unsigned long long value) { constexpr ElectronReducedComptonWavelength operator""__e(long double value) { return ElectronReducedComptonWavelength(static_cast(value)); } -constexpr ElectronReducedComptonWavelength operator""__e(unsigned long long value) { +constexpr ElectronReducedComptonWavelength +operator""__e(unsigned long long value) { return ElectronReducedComptonWavelength(static_cast(value)); } @@ -315,7 +316,8 @@ constexpr NominalLunarDistance operator""_LD(unsigned long long value) { constexpr NominalEarthPolarRadius operator""_R_earthpol(long double value) { return NominalEarthPolarRadius(static_cast(value)); } -constexpr NominalEarthPolarRadius operator""_R_earthpol(unsigned long long value) { +constexpr NominalEarthPolarRadius +operator""_R_earthpol(unsigned long long value) { return NominalEarthPolarRadius(static_cast(value)); } @@ -329,21 +331,24 @@ constexpr NominalEarthRadius operator""_R_earth(unsigned long long value) { constexpr NominalEarthEquatorialRadius operator""_R_eartheq(long double value) { return NominalEarthEquatorialRadius(static_cast(value)); } -constexpr NominalEarthEquatorialRadius operator""_R_eartheq(unsigned long long value) { +constexpr NominalEarthEquatorialRadius +operator""_R_eartheq(unsigned long long value) { return NominalEarthEquatorialRadius(static_cast(value)); } constexpr EarthMeridionalCircumference operator""_C_mer(long double value) { return EarthMeridionalCircumference(static_cast(value)); } -constexpr EarthMeridionalCircumference operator""_C_mer(unsigned long long value) { +constexpr EarthMeridionalCircumference +operator""_C_mer(unsigned long long value) { return EarthMeridionalCircumference(static_cast(value)); } constexpr EarthEquatorialCircumference operator""_C_eq(long double value) { return EarthEquatorialCircumference(static_cast(value)); } -constexpr EarthEquatorialCircumference operator""_C_eq(unsigned long long value) { +constexpr EarthEquatorialCircumference +operator""_C_eq(unsigned long long value) { return EarthEquatorialCircumference(static_cast(value)); } diff --git a/include/qtty/serialization.hpp b/include/qtty/serialization.hpp index a6270c5..76182fd 100644 --- a/include/qtty/serialization.hpp +++ b/include/qtty/serialization.hpp @@ -156,14 +156,13 @@ namespace derived_serialization { * @param q Source compound quantity. * @return JSON string. */ -template -std::string to_json(const Quantity &q) { +template std::string to_json(const Quantity &q) { static_assert(is_compound_v, "derived_serialization::to_json requires a compound quantity"); qtty_derived_quantity_t src{}; - int32_t status = qtty_derived_make( - q.value(), UnitTraits::numerator_unit_id(), - UnitTraits::denominator_unit_id(), &src); + int32_t status = + qtty_derived_make(q.value(), UnitTraits::numerator_unit_id(), + UnitTraits::denominator_unit_id(), &src); check_status(status, "Creating derived quantity for serialization"); char *out = nullptr; @@ -191,9 +190,9 @@ Quantity::type> from_json(std::string_view json) { if (out_qty.numerator != UnitTraits::numerator_unit_id() || out_qty.denominator != UnitTraits::denominator_unit_id()) { qtty_derived_quantity_t conv{}; - status = qtty_derived_convert( - out_qty, UnitTraits::numerator_unit_id(), - UnitTraits::denominator_unit_id(), &conv); + status = + qtty_derived_convert(out_qty, UnitTraits::numerator_unit_id(), + UnitTraits::denominator_unit_id(), &conv); check_status(status, "Converting deserialized derived quantity"); return Quantity(conv.value); } diff --git a/include/qtty/units/length.hpp b/include/qtty/units/length.hpp index 67efda6..f0c629a 100644 --- a/include/qtty/units/length.hpp +++ b/include/qtty/units/length.hpp @@ -151,11 +151,15 @@ template <> struct UnitTraits { static constexpr std::string_view symbol() { return "a₀"; } }; template <> struct UnitTraits { - static constexpr UnitId unit_id() { return UNIT_ID_CLASSICAL_ELECTRON_RADIUS; } + 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 UnitId unit_id() { + return UNIT_ID_ELECTRON_REDUCED_COMPTON_WAVELENGTH; + } static constexpr std::string_view symbol() { return "λ̄_e"; } }; template <> struct UnitTraits { @@ -227,7 +231,9 @@ template <> struct UnitTraits { 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 UnitId unit_id() { + return UNIT_ID_NOMINAL_EARTH_POLAR_RADIUS; + } static constexpr std::string_view symbol() { return "R_⊕pol"; } }; template <> struct UnitTraits { @@ -235,15 +241,21 @@ template <> struct UnitTraits { 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 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 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 UnitId unit_id() { + return UNIT_ID_EARTH_EQUATORIAL_CIRCUMFERENCE; + } static constexpr std::string_view symbol() { return "C_eq"; } }; template <> struct UnitTraits { @@ -283,7 +295,8 @@ using Zettameter = Quantity; using Yottameter = Quantity; using BohrRadius = Quantity; using ClassicalElectronRadius = Quantity; -using ElectronReducedComptonWavelength = Quantity; +using ElectronReducedComptonWavelength = + Quantity; using AstronomicalUnit = Quantity; using LightYear = Quantity; using Parsec = Quantity; diff --git a/tests/test_derived.cpp b/tests/test_derived.cpp index 68c58ca..12efd80 100644 --- a/tests/test_derived.cpp +++ b/tests/test_derived.cpp @@ -50,7 +50,7 @@ TEST_F(DerivedQuantityTest, VelocityFromDivision) { // Create velocity from actual division Kilometer dist(180.0); Hour t(2.0); - auto v = dist / t; // type: KilometerPerHour + auto v = dist / t; // type: KilometerPerHour EXPECT_NEAR(v.value(), 90.0, 1e-12);