| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859 |
- /**
- * Utility functions for managing numeric types - such as converting between
- * floating-point and integer types.
- *
- * None of these are particularly complex functions, but storing them in a
- * single header with descriptive names helps the reader quickly recognize what
- * is being done.
- */
- #pragma once
- #include <charconv>
- #include <cmath>
- #include <concepts>
- #include <cstdint>
- #include <limits>
- #include <stdexcept>
- #include <string>
- #include <string_view>
- #include <system_error>
- namespace jvalidate::detail {
- /**
- * @brief Determine if a floating point number is actually an integer (in the
- * mathematical sense).
- */
- inline bool is_json_integer(double number) { return std::floor(number) == number; }
- /**
- * @brief Determine if a floating point number is actually an integer, and
- * actually fits in the 64-bit integer type that we use for JSON Integer.
- */
- inline bool fits_in_integer(double number) {
- static constexpr auto g_int_max = static_cast<double>(std::numeric_limits<int64_t>::max());
- static constexpr auto g_int_min = static_cast<double>(std::numeric_limits<int64_t>::min());
- return is_json_integer(number) && number <= g_int_max && number >= g_int_min;
- }
- /**
- * @brief Determine if an unsigned integer fits into a signed integer
- */
- // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers)
- inline bool fits_in_integer(uint64_t number) { return (number & 0x8000'0000'0000'0000) == 0; }
- // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers)
- template <std::integral I> I from_str(std::string_view str, int base = 10) {
- I rval;
- auto [end, ec] = std::from_chars(str.begin(), str.end(), rval, base);
- if (ec != std::errc{}) {
- throw std::runtime_error(std::make_error_code(ec).message());
- }
- if (end != str.end()) {
- throw std::runtime_error("NaN: " + std::string(str));
- }
- return rval;
- }
- }
|