|
1 | 1 | module; |
2 | 2 | #include <atomic> |
| 3 | +#include <cmath> |
3 | 4 | #include <cstdint> |
4 | 5 | #include <concepts> |
5 | 6 | #include <exception> |
@@ -574,6 +575,64 @@ constexpr auto narrow_integral_error(SrcRep value) |
574 | 575 | return std::nullopt; |
575 | 576 | } |
576 | 577 | } |
| 578 | + |
| 579 | +template <typename DestRep, typename SrcRep> |
| 580 | +constexpr auto narrow_numeric_error(SrcRep value) |
| 581 | + -> std::optional<error::kind> { |
| 582 | + using dest_type = std::remove_cv_t<DestRep>; |
| 583 | + using src_type = std::remove_cv_t<SrcRep>; |
| 584 | + |
| 585 | + if constexpr (std::integral<dest_type> && std::integral<src_type>) { |
| 586 | + return narrow_integral_error<dest_type>(value); |
| 587 | + } else if constexpr (std::integral<dest_type> && |
| 588 | + std::floating_point<src_type>) { |
| 589 | + if (std::isnan(value)) { |
| 590 | + return error::kind::domain_error; |
| 591 | + } |
| 592 | + if (std::isinf(value)) { |
| 593 | + return value < static_cast<src_type>(0) ? error::kind::underflow |
| 594 | + : error::kind::overflow; |
| 595 | + } |
| 596 | + |
| 597 | + auto const normalized = static_cast<long double>(value); |
| 598 | + auto const min_value = |
| 599 | + static_cast<long double>(std::numeric_limits<dest_type>::lowest()); |
| 600 | + auto const max_value = |
| 601 | + static_cast<long double>(std::numeric_limits<dest_type>::max()); |
| 602 | + |
| 603 | + if (normalized < min_value) { |
| 604 | + return error::kind::underflow; |
| 605 | + } |
| 606 | + if (normalized > max_value) { |
| 607 | + return error::kind::overflow; |
| 608 | + } |
| 609 | + return std::nullopt; |
| 610 | + } else { |
| 611 | + static_cast<void>(value); |
| 612 | + return std::nullopt; |
| 613 | + } |
| 614 | +} |
| 615 | + |
| 616 | +template <typename DestRep, typename SrcRep> |
| 617 | +constexpr auto safe_numeric_cast(SrcRep value) noexcept -> DestRep { |
| 618 | + using dest_type = std::remove_cv_t<DestRep>; |
| 619 | + using src_type = std::remove_cv_t<SrcRep>; |
| 620 | + |
| 621 | + if constexpr (std::integral<dest_type> && std::floating_point<src_type>) { |
| 622 | + if (auto const kind = narrow_numeric_error<dest_type>(value); |
| 623 | + kind.has_value()) { |
| 624 | + if (*kind == error::kind::overflow) { |
| 625 | + return std::numeric_limits<dest_type>::max(); |
| 626 | + } |
| 627 | + if (*kind == error::kind::underflow) { |
| 628 | + return std::numeric_limits<dest_type>::lowest(); |
| 629 | + } |
| 630 | + return dest_type{}; |
| 631 | + } |
| 632 | + } |
| 633 | + |
| 634 | + return static_cast<dest_type>(value); |
| 635 | +} |
577 | 636 | } // namespace details |
578 | 637 |
|
579 | 638 | template <operations::operation OpTag, typename CommonRep, |
|
0 commit comments