Add _mag UDLs#677
Conversation
Using the templated version lets us return a separate type for each number, exactly as we need! This should be a nice readable alternative.
There was a problem hiding this comment.
Pull request overview
Adds a _mag user-defined literal as a more concise, readable alternative to the mag<N>() helper for forming Magnitude instances. The UDL lives in a dedicated au::au_literals namespace (to be opted into via using namespace), and is documented alongside the existing magnitude-formation options.
Changes:
- Declare and define
operator""_maginau::au_literals, backed by aconstexprdigit parserdetail::parse_magnitude_integer. - Document the new literal (and renumber the existing list) in
docs/reference/magnitude.md. - Add tests covering type/value equivalence with
mag<N>(), digit separators, and constexpr use.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| docs/reference/magnitude.md | Updates the list of valid Magnitude formation methods to include the new _mag UDL and adds a dedicated section explaining usage. |
| au/magnitude.hh | Declares operator""_mag in au::au_literals, and implements it via a constexpr digit-parsing helper. |
| au/magnitude_test.cc | Adds tests verifying the UDL matches mag<N>() in type and value, including with digit separators and in a constexpr context. |
Comments suppressed due to low confidence (1)
au/magnitude.hh:685
- There is no overflow check in
parse_magnitude_integer. If a user writes a literal larger thanstd::uintmax_tcan hold (e.g.,99999999999999999999_mag), the multiplication/addition silently wraps around modulo2^N, and the resultingmag<...>()will be a completely different (and arbitrary) magnitude with no diagnostic. Consider adding astatic_assert(e.g., by checking thatresult * 10u + digitdoes not overflow at each step, possibly viaconstexproverflow-checked arithmetic) so that out-of-range literals fail to compile with a clear message.
constexpr std::uintmax_t parse_magnitude_integer() {
constexpr char digits[] = {Cs...};
std::uintmax_t result = 0u;
for (std::size_t i = 0u; i < sizeof...(Cs); ++i) {
if (digits[i] >= '0' && digits[i] <= '9') {
result = result * 10u + static_cast<std::uintmax_t>(digits[i] - '0');
}
}
return result;
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
geoffviola
left a comment
There was a problem hiding this comment.
Looks useful. Implementation, tests, and documentation look good.
hoffbrinkle
left a comment
There was a problem hiding this comment.
Are there any downsides to this? The type limitations of a UDL wouldn't be a problem here (since the template parameter needs to be an unsigned int). Any compile time cost?
Great questions. I was kind of wondering about compile time cost myself. This gives me the push I need: I'll set up some overnight measurements. |
|
I can already rule out any kind of noticeable compile time regression, so I'll go ahead and merge this in, but I'll share higher-statistics results on our slack channel when I have them. |
Using the templated version lets us return a separate type for each
number, exactly as we need! This should be a nice readable alternative.