safe_int, constrained, their error policies, and the safe_iN aliases are
non-framework add-ons, so their public names move out of mp_units into the
mp_units::utility extension tier (next to the representation concepts already
there). The headers move to core/include/mp-units/utility/ accordingly but stay
in the core component: safe_int reuses the core 128-bit integer toolkit
(integral, is_signed_v, int128_t, ...) that also backs the scaling engine, so it
bridges to mp_units::detail with a single using-directive rather than relocating
or duplicating that toolkit. overflow_policies stays framework (it backs bounded
quantity point origins). No deprecation shims: these types are unreleased.
Also fixes utility/representation.h, whose public concepts delegated via the
unqualified detail::X. That resolved to mp_units::detail only as long as
mp_units::utility::detail did not exist; now that constrained/safe_int introduce
it, the references are qualified to ::mp_units::detail:: so they stay
order-independent (this surfaced only in the module build).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the `disable_vector`/`disable_tensor` opt-outs with intrinsic,
adapter-overridable traits and split representation classification into two tiers.
- `customization_points.h` now owns the customizable surface: the `real`/`imag`/
`modulus` CPOs plus the `numeric_field` (field axis) and `tensor_order` (order
axis) traits. Adapters specialize these; the derived concepts stay with the
rest of the concept model in `representation_concepts.h`.
- `numeric_field` is the single source of truth for the field axis (default:
`real()`/`imag()` API detection). Field matching is exact and disjoint - a real
quantity needs a real representation and a complex one a complex representation.
- `tensor_order` is detected structurally (two-index access -> 2, one-index -> 1,
otherwise 0) and overridable. Order matching is rank-ordered: a lower-order
representation fills a higher-order slot.
- Character concepts (`Real`/`Complex`, rank-ordered `Scalar`/`Vector`/`Tensor`)
carry no representation-validity, so in V3 they can also classify a quantity by
its character. The `*Representation` concepts are `NotQuantity`-first + character
+ `UnitMagnitudeScalable`; leading with `NotQuantity` rejects a quantity before
its operators are instantiated, avoiding a constraint-satisfaction cycle.
- Eigen/Blaze adapters declare `numeric_field` from their element type (they expose
`real()`/`imag()` on real types too, which the API default would misread as complex).
- Rename `MagnitudeScalable` -> `UnitMagnitudeScalable` and `UsesMagnitudeAwareScaling`
-> `UsesUnitMagnitudeAwareScaling` to disambiguate scaling by a `unit_magnitude`
from the value/L2 magnitude (the `magnitude` CPO).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds heterogeneous arithmetic operators (+ - * / %) to `detail::safe_int_binary_ops`,
following the same idiom already used for `==` and `<=>`. The non-template homogeneous
inline-friends inside `safe_int<T>` keep winning same-T calls; the new template friends
in the base unambiguously handle the T != U calls without changing the converting-ctor
semantics. Resolves the ambiguity that triggered C2666 on `safe_int<int> + safe_int<long>`
when `int` and `long` have equal width (Windows).
Also:
* `mul_overflows<T>` now gates on `integer_rep_width_v<int128_t>` so MSVC's synthetic
`double_width_int<int64_t>` counts as a usable wider type for the overflow check.
* Replace the platform-dependent `safe_int<long>` widening test with a portable
`long long` variant — on Windows the original test's RHS
`static_cast<long>(INT_MAX) + 1L` is itself constexpr-invalid 32-bit overflow.
* Add convertibility coverage tests for `safe_int<T> op raw_U` mixing short / int /
long / uint8_t to lock down that the `safe_int op integral` overload wins by exact
match over the converting ctor on every platform.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>