2025-06-22 19:53:49 +08:00
|
|
|
#pragma once
|
2025-06-30 08:45:18 +08:00
|
|
|
#include "../string/reinterpret.hpp"
|
2025-07-25 09:35:26 +08:00
|
|
|
#include <string>
|
2025-06-22 19:53:49 +08:00
|
|
|
#include <array>
|
2025-07-25 09:35:26 +08:00
|
|
|
#include <type_traits>
|
2025-06-22 19:53:49 +08:00
|
|
|
#include <charconv>
|
|
|
|
#include <stdexcept>
|
|
|
|
|
|
|
|
#define NS_YYCC_STRING_REINTERPRET ::yycc::string::reinterpret
|
|
|
|
|
2025-06-25 10:40:05 +08:00
|
|
|
/**
|
|
|
|
* @brief Provides stringify utilities for converting numeric and boolean values to strings.
|
|
|
|
* @details
|
|
|
|
* This namespace contains functions for stringifying various numeric types (integer, floating point)
|
|
|
|
* and boolean values into string. It uses \c std::to_chars internally for efficient stringify.
|
|
|
|
* @remarks
|
|
|
|
* See https://en.cppreference.com/w/cpp/utility/to_chars for underlying called functions.
|
|
|
|
* Default float precision = 6 is gotten from: https://en.cppreference.com/w/c/io/fprintf
|
|
|
|
*/
|
2025-06-30 08:45:18 +08:00
|
|
|
namespace yycc::num::stringify {
|
2025-06-22 19:53:49 +08:00
|
|
|
|
2025-06-23 16:22:55 +08:00
|
|
|
/// @private
|
2025-06-25 10:40:05 +08:00
|
|
|
/// @brief Size of the internal buffer used for string conversion.
|
2025-06-22 19:53:49 +08:00
|
|
|
inline constexpr size_t STRINGIFY_BUFFER_SIZE = 64u;
|
2025-06-23 16:22:55 +08:00
|
|
|
/// @private
|
2025-06-25 10:40:05 +08:00
|
|
|
/// @brief Type alias for the buffer used in string conversion.
|
2025-07-25 09:35:26 +08:00
|
|
|
using StringifyBuffer = std::array<char8_t, STRINGIFY_BUFFER_SIZE>;
|
2025-06-22 19:53:49 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Return the string representation of given floating point value.
|
|
|
|
* @tparam T The type derived from floating point type.
|
|
|
|
* @param[in] num The value need to get string representation.
|
|
|
|
* @param[in] fmt The floating point format used when getting string representation.
|
|
|
|
* @param[in] precision The floating point precision used when getting string representation.
|
|
|
|
* @return The string representation of given value.
|
|
|
|
*/
|
2025-07-25 09:35:26 +08:00
|
|
|
template<typename T>
|
|
|
|
requires(std::is_floating_point_v<T>)
|
|
|
|
std::u8string stringify(T num, std::chars_format fmt = std::chars_format::general, int precision = 6) {
|
2025-06-22 19:53:49 +08:00
|
|
|
namespace reinterpret = NS_YYCC_STRING_REINTERPRET;
|
2025-07-14 09:13:47 +08:00
|
|
|
|
2025-06-22 19:53:49 +08:00
|
|
|
StringifyBuffer buffer;
|
|
|
|
auto [ptr, ec] = std::to_chars(reinterpret::as_ordinary(buffer.data()),
|
|
|
|
reinterpret::as_ordinary(buffer.data() + buffer.size()),
|
|
|
|
num,
|
|
|
|
fmt,
|
|
|
|
precision);
|
|
|
|
if (ec == std::errc()) {
|
2025-07-25 09:35:26 +08:00
|
|
|
return std::u8string(buffer.data(), reinterpret::as_utf8(ptr) - buffer.data());
|
2025-06-22 19:53:49 +08:00
|
|
|
} else if (ec == std::errc::value_too_large) {
|
2025-06-23 16:22:55 +08:00
|
|
|
// Too short buffer. This should not happen.
|
2025-06-22 19:53:49 +08:00
|
|
|
throw std::out_of_range("stringify() buffer is not sufficient.");
|
|
|
|
} else {
|
|
|
|
// Unreachable
|
|
|
|
throw std::runtime_error("unreachable code.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* @brief Return the string representation of given integral value.
|
|
|
|
* @tparam T The type derived from integral type except bool type.
|
|
|
|
* @param[in] num The value need to get string representation.
|
|
|
|
* @param[in] base Integer base used when getting string representation: a value between 2 and 36 (inclusive).
|
|
|
|
* @return The string representation of given value.
|
|
|
|
*/
|
2025-07-25 09:35:26 +08:00
|
|
|
template<typename T>
|
|
|
|
requires(std::is_integral_v<T> && !std::is_same_v<T, bool>)
|
|
|
|
std::u8string stringify(T num, int base = 10) {
|
2025-06-22 19:53:49 +08:00
|
|
|
namespace reinterpret = NS_YYCC_STRING_REINTERPRET;
|
2025-07-25 09:35:26 +08:00
|
|
|
|
2025-06-22 19:53:49 +08:00
|
|
|
StringifyBuffer buffer;
|
|
|
|
auto [ptr, ec] = std::to_chars(reinterpret::as_ordinary(buffer.data()),
|
|
|
|
reinterpret::as_ordinary(buffer.data() + buffer.size()),
|
|
|
|
num,
|
|
|
|
base);
|
|
|
|
if (ec == std::errc()) {
|
2025-07-25 09:35:26 +08:00
|
|
|
return std::u8string(buffer.data(), reinterpret::as_utf8(ptr) - buffer.data());
|
2025-06-22 19:53:49 +08:00
|
|
|
} else if (ec == std::errc::value_too_large) {
|
2025-06-23 16:22:55 +08:00
|
|
|
// Too short buffer. This should not happen.
|
2025-06-22 19:53:49 +08:00
|
|
|
throw std::out_of_range("stringify() buffer is not sufficient.");
|
|
|
|
} else {
|
|
|
|
// Unreachable
|
|
|
|
throw std::runtime_error("unreachable code.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* @brief Return the string representation of given bool value.
|
|
|
|
* @tparam T The type derived from bool type.
|
|
|
|
* @param[in] num The value need to get string representation.
|
|
|
|
* @return The string representation of given value ("true" or "false").
|
|
|
|
*/
|
2025-07-25 09:35:26 +08:00
|
|
|
template<typename T>
|
|
|
|
requires(std::is_same_v<T, bool>)
|
|
|
|
std::u8string stringify(T num) {
|
|
|
|
if (num) return std::u8string(u8"true");
|
|
|
|
else return std::u8string(u8"false");
|
2025-06-22 19:53:49 +08:00
|
|
|
}
|
|
|
|
|
2025-07-25 09:35:26 +08:00
|
|
|
} // namespace yycc::num::stringify
|
2025-06-22 19:53:49 +08:00
|
|
|
|
|
|
|
#undef NS_YYCC_STRING_REINTERPRET
|