dimval 0.2.0
Modern C++23 header-only library of dimensional values (units, measures, ranges)
Loading...
Searching...
No Matches
measure.hpp
Go to the documentation of this file.
1#pragma once
2
5
6#include <dimval/core.hpp>
8#include <dimval/traits.hpp>
9#include <dimval/unit.hpp>
10
11#include <commons/color.hpp>
12#include <commons/icon.hpp>
13
14#include <expected>
15#include <memory>
16#include <optional>
17#include <string>
18#include <string_view>
19
20namespace dimval {
21
30template <MeasureLike M, NumericValue T = double>
31struct MeasureValue : public IMeasureValue {
32 using measure_t = M;
33 using unit_t = M::base_unit_t;
34 using value_t = T;
35
36 T v{};
37
38 constexpr MeasureValue() = default;
42 constexpr MeasureValue(T value) noexcept : v(value) {} // NOLINT(google-explicit-constructor)
43
46 [[nodiscard]] static std::shared_ptr<MeasureValue> of(T value) {
47 return std::make_shared<MeasureValue>(value);
48 }
49
51 [[nodiscard]] static std::unique_ptr<MeasureValue> unique(T value) {
52 return std::make_unique<MeasureValue>(value);
53 }
54
56 [[nodiscard]] static std::expected<MeasureValue, ParseError> parse(std::string_view input) {
57 auto u = UnitValue<unit_t, T>::parse(input);
58 if (!u)
59 return std::unexpected{u.error()};
60 return MeasureValue{u->v};
61 }
62
63 // Compile-time metadata accessors -----------------------------------------
64 // Read straight off the measure / unit tag, no descriptor round-trip.
65 [[nodiscard]] static constexpr std::string_view id() noexcept {
66 return M::id;
67 }
68 [[nodiscard]] static constexpr std::string_view unit_id() noexcept {
69 return unit_t::id;
70 }
71 [[nodiscard]] static constexpr std::string_view name() noexcept {
72 return M::name;
73 }
74 [[nodiscard]] static constexpr std::string_view symbol() noexcept {
75 return unit_t::symbol;
76 }
77 [[nodiscard]] static constexpr std::string_view kind() noexcept {
78 return unit_t::kind;
79 }
80 [[nodiscard]] static constexpr std::optional<comms::Icon> icon() noexcept {
81 return M::icon ? M::icon : unit_t::icon;
82 }
83 [[nodiscard]] static constexpr std::optional<comms::Color> color() noexcept {
84 return M::color ? M::color : unit_t::color;
85 }
86
88 [[nodiscard]] constexpr UnitValue<unit_t, T> as_unit_value() const noexcept {
89 return UnitValue<unit_t, T>{v};
90 }
91
92 // IMeasureValue overrides -------------------------------------------------
93 // Only the descriptors stay virtual — per-field metadata is reachable via
94 // `descriptor().name`, `unit_descriptor().symbol`, ... from a polymorphic
95 // handle.
96 [[nodiscard]] MeasureDescriptor descriptor() const noexcept override {
97 return M::descriptor();
98 }
99 [[nodiscard]] UnitDescriptor unit_descriptor() const noexcept override {
100 return unit_t::descriptor();
101 }
102 [[nodiscard]] double numeric_as_double() const noexcept override {
103 return static_cast<double>(v);
104 }
105
106 [[nodiscard]] std::string to_string() const override;
107 [[nodiscard]] std::string to_formatted_string() const override;
108
109 [[nodiscard]] std::unique_ptr<IMeasureValue> clone() const override {
110 return std::make_unique<MeasureValue>(*this);
111 }
112
113 [[nodiscard]] friend constexpr bool operator==(const MeasureValue& a,
114 const MeasureValue& b) noexcept {
115 return a.v == b.v;
116 }
117 [[nodiscard]] friend constexpr auto operator<=>(const MeasureValue& a,
118 const MeasureValue& b) noexcept {
119 return a.v <=> b.v;
120 }
121
122 constexpr MeasureValue& operator+=(const MeasureValue& rhs) noexcept {
123 v += rhs.v;
124 return *this;
125 }
126 constexpr MeasureValue& operator-=(const MeasureValue& rhs) noexcept {
127 v -= rhs.v;
128 return *this;
129 }
130 constexpr MeasureValue& operator*=(T s) noexcept {
131 v *= s;
132 return *this;
133 }
134 constexpr MeasureValue& operator/=(T s) noexcept {
135 v /= s;
136 return *this;
137 }
138};
139
140template <MeasureLike M, NumericValue T>
141[[nodiscard]] constexpr MeasureValue<M, T> operator+(const MeasureValue<M, T>& a,
142 const MeasureValue<M, T>& b) noexcept {
143 return MeasureValue<M, T>{static_cast<T>(a.v + b.v)};
144}
145
146template <MeasureLike M, NumericValue T>
147[[nodiscard]] constexpr MeasureValue<M, T> operator-(const MeasureValue<M, T>& a,
148 const MeasureValue<M, T>& b) noexcept {
149 return MeasureValue<M, T>{static_cast<T>(a.v - b.v)};
150}
151
152template <MeasureLike M, NumericValue T>
153[[nodiscard]] constexpr MeasureValue<M, T> operator-(const MeasureValue<M, T>& a) noexcept {
154 return MeasureValue<M, T>{static_cast<T>(-a.v)};
155}
156
157template <MeasureLike M, NumericValue T>
158[[nodiscard]] constexpr MeasureValue<M, T> operator+(const MeasureValue<M, T>& a) noexcept {
159 return a;
160}
161
162template <MeasureLike M, NumericValue T>
163[[nodiscard]] constexpr MeasureValue<M, T> operator*(const MeasureValue<M, T>& a, T s) noexcept {
164 return MeasureValue<M, T>{static_cast<T>(a.v * s)};
165}
166
167template <MeasureLike M, NumericValue T>
168[[nodiscard]] constexpr MeasureValue<M, T> operator*(T s, const MeasureValue<M, T>& a) noexcept {
169 return MeasureValue<M, T>{static_cast<T>(a.v * s)};
170}
171
172template <MeasureLike M, NumericValue T>
173[[nodiscard]] constexpr MeasureValue<M, T> operator/(const MeasureValue<M, T>& a, T s) noexcept {
174 return MeasureValue<M, T>{static_cast<T>(a.v / s)};
175}
176
177template <MeasureLike M, NumericValue T>
178[[nodiscard]] constexpr T operator/(const MeasureValue<M, T>& a,
179 const MeasureValue<M, T>& b) noexcept {
180 return static_cast<T>(a.v / b.v);
181}
182
185template <MeasureLike M, NumericValue T>
186[[nodiscard]] constexpr MeasureValue<M, T>
190
192template <MeasureLike M, NumericValue T = double>
193[[nodiscard]] constexpr MeasureValue<M, T> measure_value(T v) noexcept {
194 return MeasureValue<M, T>{v};
195}
196
197} // namespace dimval
Polymorphic interface implemented by every MeasureValue<M,T>.
Definition interface.hpp:59
Common concepts, error types, and small utilities used across dimval.
Abstract interfaces for runtime polymorphic handling of dimensional values.
constexpr MeasureValue< M, T > from_unit_value(const UnitValue< typename M::base_unit_t, T > &u) noexcept
Wrap a UnitValue<base_unit_of<M>> as a MeasureValue<M>.
Definition measure.hpp:187
constexpr MeasureValue< M, T > measure_value(T v) noexcept
Sugar: produce a MeasureValue from a scalar literal.
Definition measure.hpp:193
Runtime metadata for a measure (a semantic specialization of a unit).
Definition descriptor.hpp:54
A value carrying both a measure tag and a unit tag.
Definition measure.hpp:31
static std::unique_ptr< MeasureValue > unique(T value)
Heap-allocated unique-owned factory.
Definition measure.hpp:51
static std::expected< MeasureValue, ParseError > parse(std::string_view input)
Parse "100 m" → MeasureValue<M,T>. Forwards to UnitValue<base_unit_t,T>::parse.
Definition measure.hpp:56
constexpr MeasureValue(T value) noexcept
Implicit conversion from the numeric type — enables DistanceValue d = 1500.0; style construction.
Definition measure.hpp:42
static std::shared_ptr< MeasureValue > of(T value)
Heap-allocated shared-owned factory: auto d = DistanceValue::of(1500.0); For a stack value,...
Definition measure.hpp:46
UnitDescriptor unit_descriptor() const noexcept override
Underlying unit's descriptor — read unit_descriptor().id, .symbol, etc.
Definition measure.hpp:99
MeasureDescriptor descriptor() const noexcept override
Measure descriptor — read fields like descriptor().name from here.
Definition measure.hpp:96
constexpr UnitValue< unit_t, T > as_unit_value() const noexcept
Drop the measure tag and expose the underlying UnitValue.
Definition measure.hpp:88
Runtime metadata for a unit.
Definition descriptor.hpp:29
A value paired at the type level with a unit tag.
Definition unit.hpp:36
static std::expected< UnitValue, ParseError > parse(const std::string_view input)
Parse "42.5 m" → UnitValue<U,T>.
Definition unit.hpp:62
Concepts and helper accessors that drive the static side of dimval.
UnitValue<U,T>: a strongly-typed value carrying a compile-time unit tag.