1#ifndef NEFORCE_CORE_STRING_FORMAT_HPP__
2#define NEFORCE_CORE_STRING_FORMAT_HPP__
13NEFORCE_BEGIN_NAMESPACE__
71constexpr format_align to_number_alignment(
const char c) {
123 if (fmt_str.
empty()) {
127 bool found_align =
false;
128 if (pos + 1 < fmt_str.
size()) {
129 const char first_char = fmt_str[pos];
130 const char second_char = fmt_str[pos + 1];
132 if (second_char ==
'<' || second_char ==
'>' || second_char ==
'^' || second_char ==
'=') {
133 if (first_char !=
'+' && first_char !=
'-' && first_char !=
' ') {
134 options.
fill = first_char;
135 options.
align = to_number_alignment(second_char);
142 if (!found_align && pos < fmt_str.
size()) {
143 const char c = fmt_str[pos];
144 if (c ==
'<' || c ==
'>' || c ==
'^' || c ==
'=') {
145 options.
align = to_number_alignment(c);
150 if (pos < fmt_str.
size()) {
151 const char c = fmt_str[pos];
155 }
else if (c ==
' ') {
158 }
else if (c ==
'-') {
160 if (pos < fmt_str.
size()) {
161 const char next = fmt_str[pos];
163 options.
align = to_number_alignment(
next);
170 if (pos < fmt_str.
size() && fmt_str[pos] ==
'#') {
183 while (pos < fmt_str.
size() &&
is_digit(fmt_str[pos])) {
184 width = width * 10 + (fmt_str[pos] -
'0');
187 options.
width = width;
190 if (pos < fmt_str.
size() && fmt_str[pos] ==
'.') {
193 while (pos < fmt_str.
size() &&
is_digit(fmt_str[pos])) {
194 precision = precision * 10 + (fmt_str[pos] -
'0');
200 if (pos < fmt_str.
size()) {
201 const char c = fmt_str[pos];
202 options.
type = to_number_type(c);
203 if (c ==
'X' || c ==
'E' || c ==
'G' || c ==
'B') {
213NEFORCE_CONSTEXPR20
string apply_format_options(
string raw,
const format_options& options,
214 const bool is_numeric =
false) {
215 char existing_sign =
'\0';
216 if (!raw.
empty() && (raw[0] ==
'-' || raw[0] ==
'+' || raw[0] ==
' ')) {
219 existing_sign =
sign;
224 switch (options.
type) {
226 prefix = options.
uppercase ?
"0X" :
"0x";
230 prefix = options.
uppercase ?
"0B" :
"0b";
234 if (raw.
empty() || raw[0] !=
'0') {
246 if (existing_sign ==
'-') {
254 const size_t content_len = sign_str.
size() + prefix.
size() + raw.
size();
255 const size_t target_width = (options.
width > 0) ?
static_cast<size_t>(options.
width) : 0;
257 const size_t pad_total = (content_len < target_width) ? target_width - content_len : 0;
269 const char fill_char = options.
fill;
271 result.
reserve(target_width > 0 ? target_width : content_len);
274 for (
size_t i = 0; i < pad_total; ++i) {
281 const char fill_char = options.
fill;
287 right_pad =
string(pad_total, fill_char);
291 const size_t left_count = pad_total / 2;
292 const size_t right_count = pad_total - left_count;
293 left_pad =
string(left_count, fill_char);
294 right_pad =
string(right_count, fill_char);
299 left_pad =
string(pad_total, fill_char);
305 result.
reserve(target_width > 0 ? target_width : content_len);
314template <
typename T,
bool Signed>
315struct integer_formatter_impl {
316 NEFORCE_CONSTEXPR20
string operator()(
const T value,
const format_options& options)
const {
320 const UT abs_value =
is_negative ?
static_cast<UT
>(0 -
static_cast<UT
>(value)) : static_cast<UT>(value);
325 switch (options.
type) {
326 case format_type::BINARY: {
327 raw = inner::__uint_to_string_base(compatible, 2, options.uppercase);
331 raw = inner::__uint_to_string_base(compatible, 8, options.uppercase);
335 raw = inner::__uint_to_string_base(compatible, 16, options.uppercase);
339 return inner::apply_format_options(string(1, static_cast<char>(value)), options, false);
344 raw = inner::__int_to_string_dispatch(value);
345 return inner::apply_format_options(_NEFORCE move(raw), options, true);
352 return inner::apply_format_options(_NEFORCE
move(raw), options,
true);
367template <
typename Number,
typename Dummy =
void>
386 switch (options.
type) {
416 return inner::apply_format_options(_NEFORCE
move(raw), options,
true);
433 return inner::integer_formatter_impl<T, true>{}(value, options);
450 return inner::integer_formatter_impl<T, false>{}(value, options);
459 NEFORCE_CONSTEXPR20
string operator()(
const char value,
const format_options& options)
const {
460 switch (options.
type) {
465 return inner::integer_formatter_impl<int, true>{}(
static_cast<int>(value), options);
471 return inner::apply_format_options(
string(1, value), options,
false);
477 NEFORCE_CONSTEXPR20
string operator()(
const T value,
const format_options& options)
const {
487 NEFORCE_CONSTEXPR20
string operator()(
const bool value,
const format_options& options)
const {
488 switch (options.
type) {
493 return inner::integer_formatter_impl<int, false>{}(value, options);
499 return inner::apply_format_options(value ?
"true" :
"false", options,
false);
508 NEFORCE_CONSTEXPR20
string operator()(
const string& value,
const format_options& options)
const {
513 return inner::apply_format_options(_NEFORCE
move(raw), options,
false);
532 NEFORCE_CONSTEXPR20
string operator()(
const char* value,
const format_options& options)
const {
533 if (value ==
nullptr) {
534 return inner::apply_format_options(
"nullptr", options,
false);
546 return inner::apply_format_options(
"nullptr", options,
false);
555 NEFORCE_CONSTEXPR20
string operator()(
const T* ptr,
const format_options& options)
const {
556 return inner::apply_format_options(_NEFORCE
address_string(ptr), options,
false);
565 NEFORCE_CONSTEXPR20
string operator()(
char* value,
const format_options& options)
const {
581NEFORCE_CONSTEXPR20
void format_impl(
const string_view fmt,
size_t& pos,
string& out) {
582 while (pos < fmt.
size()) {
583 if (fmt[pos] ==
'{') {
584 if (pos + 1 < fmt.
size() && fmt[pos + 1] ==
'{') {
590 }
else if (fmt[pos] ==
'}') {
591 if (pos + 1 < fmt.
size() && fmt[pos + 1] ==
'}') {
615template <
typename First,
typename... Rest>
616NEFORCE_CONSTEXPR20
void format_impl(
const string_view fmt,
size_t& pos,
string& out, First&& first, Rest&&... rest) {
617 while (pos < fmt.
size()) {
618 if (fmt[pos] ==
'{') {
619 if (pos + 1 < fmt.
size() && fmt[pos + 1] ==
'{') {
625 size_t end_pos = pos;
627 while (end_pos < fmt.
size() && depth > 0) {
628 if (fmt[end_pos] ==
'{') {
630 }
else if (fmt[end_pos] ==
'}') {
638 NEFORCE_THROW_EXCEPTION(
value_exception(
"Unmatched '{' in format string"));
645 if (spec_str.
empty()) {
646 opts = inner::parse_number_format(
"");
647 }
else if (spec_str[0] ==
':') {
648 opts = inner::parse_number_format(spec_str.
substr(1));
653 inner::format_impl(fmt, pos, out, _NEFORCE
forward<Rest>(rest)...);
655 }
else if (fmt[pos] ==
'}') {
656 if (pos + 1 < fmt.
size() && fmt[pos + 1] ==
'}') {
660 NEFORCE_THROW_EXCEPTION(
value_exception(
"Unmatched '}' in format string"));
679template <
typename... Args,
enable_if_t<(
sizeof...(Args) > 0),
int> = 0>
684 inner::format_impl(fmt, pos, result, _NEFORCE
forward<Args>(args)...);
690NEFORCE_END_NAMESPACE__
NEFORCE_NODISCARD constexpr size_type size() const noexcept
获取字符串长度
NEFORCE_NODISCARD constexpr basic_string_view substr(const size_type off=0, size_type count=npos) const
获取子视图
NEFORCE_NODISCARD constexpr bool empty() const noexcept
检查是否为空
NEFORCE_CONSTEXPR20 void reserve(const size_type n)
预留容量
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 size_type size() const noexcept
获取字符数
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 basic_string substr(const size_type off=0, size_type count=npos) const
获取子串
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 bool empty() const noexcept
检查是否为空
NEFORCE_NODISCARD constexpr T && forward(remove_reference_t< T > &x) noexcept
完美转发左值
NEFORCE_INLINE17 constexpr bool is_floating_point_v
is_floating_point的便捷变量模板
NEFORCE_INLINE17 constexpr bool is_unpackaged_v
is_unpackaged的便捷变量模板
NEFORCE_INLINE17 constexpr bool is_signed_v
is_signed的便捷变量模板
NEFORCE_INLINE17 constexpr bool is_unsigned_v
is_unsigned的便捷变量模板
NEFORCE_INLINE17 constexpr bool is_standard_integral_v
is_standard_integral的便捷变量模板
NEFORCE_INLINE17 constexpr bool is_base_of_v
is_base_of的便捷变量模板
NEFORCE_CONST_FUNCTION NEFORCE_CONSTEXPR14 bool is_digit(const CharT c) noexcept
检查字符是否为数字
unsigned char uint8_t
8位无符号整数类型
unsigned long long uint64_t
64位无符号整数类型
decltype(nullptr) nullptr_t
空指针类型
constexpr Iterator next(Iterator iter, iter_difference_t< Iterator > n=1)
获取迭代器的后一个位置
NEFORCE_CONSTEXPR14 int sign(const T &value) noexcept
获取数值的符号
NEFORCE_CONST_FUNCTION constexpr bool is_negative(const T x) noexcept
检查浮点数是否为负数
constexpr Iterator2 move(Iterator1 first, Iterator1 last, Iterator2 result) noexcept(noexcept(inner::__move_aux(first, last, result)))
移动范围元素
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string_fixed(T x, int precision=6)
将浮点数转换为字符串(固定小数格式)
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string_scientific(T x, int precision=6)
将浮点数转换为字符串(科学计数法格式)
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string to_string_general(T x, int precision=6)
将浮点数转换为字符串(通用格式)
NEFORCE_NODISCARD NEFORCE_CONSTEXPR20 string address_string(const void *p)
将指针转换为十六进制地址字符串
basic_string< char > string
字符字符串
basic_string_view< char > string_view
字符字符串视图
typename conditional< Test, T1, T2 >::type conditional_t
conditional的便捷别名
typename enable_if< Test, T >::type enable_if_t
enable_if的便捷别名