- Refactored fennec::format to use to_chars for ints. floats TODO but will also use to_chars.
This commit is contained in:
@@ -247,9 +247,13 @@ add_library(fennec STATIC
|
|||||||
|
|
||||||
# format ===============================================================================================================
|
# format ===============================================================================================================
|
||||||
include/fennec/format/format.h
|
include/fennec/format/format.h
|
||||||
include/fennec/format/detail/_format.h
|
|
||||||
include/fennec/format/format_arg.h
|
include/fennec/format/format_arg.h
|
||||||
include/fennec/format/formatter.h
|
include/fennec/format/formatter.h
|
||||||
|
include/fennec/format/charconv.h
|
||||||
|
|
||||||
|
include/fennec/format/detail/_format.h
|
||||||
|
|
||||||
|
source/format/charconv.cpp
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -49,9 +49,11 @@ Some main areas where the engine strays from the GNU standard includes the follo
|
|||||||
|
|
||||||
* [Section 4.7, Standards for Graphical Interfaces](https://www.gnu.org/prep/standards/html_node/Graphical-Interfaces.html).
|
* [Section 4.7, Standards for Graphical Interfaces](https://www.gnu.org/prep/standards/html_node/Graphical-Interfaces.html).
|
||||||
fennec provides an implementation for X11, however it does not use the GTK toolkit.
|
fennec provides an implementation for X11, however it does not use the GTK toolkit.
|
||||||
- [Section 6.1, GNU Manuals](https://www.gnu.org/prep/standards/html_node/GNU-Manuals.html)
|
- [Section 5.1, Formatting Your Source Code](https://www.gnu.org/prep/standards/html_node/index.html).
|
||||||
|
fennec uses Allman (BSD) for namespaces, otherwise K&R.
|
||||||
|
* [Section 6.1, GNU Manuals](https://www.gnu.org/prep/standards/html_node/GNU-Manuals.html)
|
||||||
fennec does not use Texinfo and instead uses Doxygen. Otherwise, it follows the other standards of this section.
|
fennec does not use Texinfo and instead uses Doxygen. Otherwise, it follows the other standards of this section.
|
||||||
* [Section 7, The Release Process](https://www.gnu.org/prep/standards/html_node/Managing-Releases.html)
|
- [Section 7, The Release Process](https://www.gnu.org/prep/standards/html_node/Managing-Releases.html)
|
||||||
fennec follows most of the conventions in this section, however the build system used is CMake and not
|
fennec follows most of the conventions in this section, however the build system used is CMake and not
|
||||||
Makefile. CMake, although overwhelming at first, is much more friendly to those who are learning build systems for the first time.
|
Makefile. CMake, although overwhelming at first, is much more friendly to those who are learning build systems for the first time.
|
||||||
|
|
||||||
|
|||||||
@@ -27,4 +27,5 @@ fennec_add_definitions(
|
|||||||
FENNEC_COMPILER_GCC=1
|
FENNEC_COMPILER_GCC=1
|
||||||
FENNEC_NO_INLINE=[[gnu::noinline]]
|
FENNEC_NO_INLINE=[[gnu::noinline]]
|
||||||
FENNEC_FUNCTION_NAME=__PRETTY_FUNCTION__
|
FENNEC_FUNCTION_NAME=__PRETTY_FUNCTION__
|
||||||
|
RYU_ONLY_64_BIT_OPS
|
||||||
)
|
)
|
||||||
|
|||||||
67
include/fennec/format/charconv.h
Normal file
67
include/fennec/format/charconv.h
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file charconv.h
|
||||||
|
/// \brief
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#ifndef FENNEC_FORMAT_CHARCONV_H
|
||||||
|
#define FENNEC_FORMAT_CHARCONV_H
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
char* to_chars(char* first, char* last, char x, int base);
|
||||||
|
char* to_chars(char* first, char* last, signed char x, int base);
|
||||||
|
char* to_chars(char* first, char* last, unsigned char x, int base);
|
||||||
|
|
||||||
|
char* to_chars(char* first, char* last, signed short x, int base);
|
||||||
|
char* to_chars(char* first, char* last, unsigned short x, int base);
|
||||||
|
|
||||||
|
char* to_chars(char* first, char* last, signed int x, int base);
|
||||||
|
char* to_chars(char* first, char* last, unsigned int x, int base);
|
||||||
|
|
||||||
|
char* to_chars(char* first, char* last, signed long x, int base);
|
||||||
|
char* to_chars(char* first, char* last, unsigned long x, int base);
|
||||||
|
|
||||||
|
char* to_chars(char* first, char* last, signed long long x, int base);
|
||||||
|
char* to_chars(char* first, char* last, unsigned long long x, int base);
|
||||||
|
|
||||||
|
char* to_chars(char* first, char* last, signed long long x, int base);
|
||||||
|
char* to_chars(char* first, char* last, unsigned long long x, int base);
|
||||||
|
|
||||||
|
char* to_chars(char* first, char* last, float x);
|
||||||
|
char* to_chars(char* first, char* last, float x, char fmt);
|
||||||
|
char* to_chars(char* first, char* last, float x, char fmt, int precision);
|
||||||
|
|
||||||
|
char* to_chars(char* first, char* last, double x);
|
||||||
|
char* to_chars(char* first, char* last, double x, char fmt);
|
||||||
|
char* to_chars(char* first, char* last, double x, char fmt, int precision);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_FORMAT_CHARCONV_H
|
||||||
@@ -45,10 +45,12 @@ string format(const cstring& str, ArgsT&&...args) {
|
|||||||
static constexpr format_arg default_fmt = {
|
static constexpr format_arg default_fmt = {
|
||||||
.fill = ' ',
|
.fill = ' ',
|
||||||
.align = '\0', // default to locale
|
.align = '\0', // default to locale
|
||||||
.sign = '\0', // default to sign only for negative numbers
|
.sign = '\0', // default to sign only for negative numbers, gets handled later in code
|
||||||
.alt = false, // default no prefix
|
.alt = false, // default no prefix
|
||||||
|
.upper = false,
|
||||||
.width = 0,
|
.width = 0,
|
||||||
.precision = 6, // default to 6 sigfigs
|
.precision = 6, // default to 6 sigfigs
|
||||||
|
.base = 10,
|
||||||
.type = '\0',
|
.type = '\0',
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -119,6 +121,7 @@ string format(const cstring& str, ArgsT&&...args) {
|
|||||||
|
|
||||||
// early return case for no colon
|
// early return case for no colon
|
||||||
if (colon > end) {
|
if (colon > end) {
|
||||||
|
fmt.sign = fmt.sign == '\0' ? '-' : fmt.sign;
|
||||||
res += argarray.format(arg, fmt);
|
res += argarray.format(arg, fmt);
|
||||||
i = end + 1;
|
i = end + 1;
|
||||||
continue;
|
continue;
|
||||||
@@ -146,12 +149,72 @@ string format(const cstring& str, ArgsT&&...args) {
|
|||||||
assert(spec < str.length() - 1 and str[spec+1] == '}', "fennec::format syntax error, mismatched '{}'");
|
assert(spec < str.length() - 1 and str[spec+1] == '}', "fennec::format syntax error, mismatched '{}'");
|
||||||
|
|
||||||
// check type
|
// check type
|
||||||
if (detail::_isfmt_t(str[spec])) {
|
switch (str[spec]) {
|
||||||
|
default: break;
|
||||||
|
|
||||||
|
case 's': case '?': // strings
|
||||||
|
case 'c': // char
|
||||||
fmt.type = str[spec--];
|
fmt.type = str[spec--];
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case 'd': // decimal
|
||||||
|
fmt.base = 10;
|
||||||
|
fmt.type = str[spec--];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'B': // binary
|
||||||
|
fmt.upper = true; [[fallthrough]];
|
||||||
|
case 'b':
|
||||||
|
fmt.base = 2;
|
||||||
|
fmt.type = str[spec--];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'o': // octal
|
||||||
|
fmt.base = 8;
|
||||||
|
fmt.type = str[spec--];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'X': // hex
|
||||||
|
fmt.upper = true; [[fallthrough]];
|
||||||
|
case 'x':
|
||||||
|
fmt.base = 16;
|
||||||
|
fmt.type = str[spec--];
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case 'A':
|
||||||
|
fmt.upper = true; [[fallthrough]];
|
||||||
|
case 'a': // float hex
|
||||||
|
fmt.base = 16;
|
||||||
|
fmt.type = str[spec--];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'E': // scientific notation
|
||||||
|
fmt.upper = true; [[fallthrough]];
|
||||||
|
case 'e':
|
||||||
|
fmt.base = 16;
|
||||||
|
fmt.type = str[spec--];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'F': // fixed precision
|
||||||
|
fmt.upper = true; [[fallthrough]];
|
||||||
|
case 'f':
|
||||||
|
fmt.base = 10;
|
||||||
|
fmt.type = str[spec--];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'G': // general precision
|
||||||
|
fmt.upper = true; [[fallthrough]];
|
||||||
|
case 'g':
|
||||||
|
fmt.base = 10;
|
||||||
|
fmt.type = str[spec--];
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// early return
|
// early return
|
||||||
if (spec == colon) {
|
if (spec == colon) {
|
||||||
|
fmt.sign = fmt.sign == '\0' ? '-' : fmt.sign;
|
||||||
res += argarray.format(arg, fmt);
|
res += argarray.format(arg, fmt);
|
||||||
i = end + 1;
|
i = end + 1;
|
||||||
continue;
|
continue;
|
||||||
@@ -218,6 +281,7 @@ string format(const cstring& str, ArgsT&&...args) {
|
|||||||
|
|
||||||
// early return
|
// early return
|
||||||
if (spec == colon) {
|
if (spec == colon) {
|
||||||
|
fmt.sign = fmt.sign == '\0' ? '-' : fmt.sign;
|
||||||
res += argarray.format(arg, fmt);
|
res += argarray.format(arg, fmt);
|
||||||
i = end + 1;
|
i = end + 1;
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -39,8 +39,9 @@ namespace fennec
|
|||||||
struct format_arg {
|
struct format_arg {
|
||||||
char fill;
|
char fill;
|
||||||
char align, sign;
|
char align, sign;
|
||||||
bool alt;
|
bool alt, upper;
|
||||||
size_t width, precision;
|
size_t width, precision;
|
||||||
|
size_t base;
|
||||||
char type;
|
char type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
#ifndef FENNEC_FORMAT_FORMATTER_H
|
#ifndef FENNEC_FORMAT_FORMATTER_H
|
||||||
#define FENNEC_FORMAT_FORMATTER_H
|
#define FENNEC_FORMAT_FORMATTER_H
|
||||||
|
|
||||||
|
#include <fennec/format/charconv.h>
|
||||||
#include <fennec/string/string.h>
|
#include <fennec/string/string.h>
|
||||||
#include <fennec/format/format_arg.h>
|
#include <fennec/format/format_arg.h>
|
||||||
|
|
||||||
@@ -80,115 +81,66 @@ struct formatter<string> {
|
|||||||
template<typename IntT> requires(is_integral_v<IntT> and not is_bool_v<IntT>)
|
template<typename IntT> requires(is_integral_v<IntT> and not is_bool_v<IntT>)
|
||||||
struct formatter<IntT> {
|
struct formatter<IntT> {
|
||||||
string operator()(const format_arg& fmt, IntT x) {
|
string operator()(const format_arg& fmt, IntT x) {
|
||||||
static constexpr char lowdigits[] = "0123456789abcdef";
|
char digits[128] = {};
|
||||||
static constexpr char highdigits[] = "0123456789ABCDEF";
|
auto chk = fennec::to_chars(digits, digits + sizeof(digits), fennec::abs(x), fmt.base);
|
||||||
bool neg = x < 0; x = fennec::abs(x);
|
assertf(chk != nullptr, "fennec::format error, to_chars error");
|
||||||
const char* digits = lowdigits;
|
size_t len = chk - digits;
|
||||||
string res;
|
|
||||||
string pre;
|
|
||||||
|
|
||||||
size_t base;
|
// handle uppercase
|
||||||
switch (fmt.type) {
|
if (fmt.upper) {
|
||||||
// decimal
|
for (auto& digit : digits) {
|
||||||
default:
|
if (digit == 0) {
|
||||||
assertf(false, "invalid format type for integral value");
|
|
||||||
[[fallthrough]];
|
|
||||||
case '\0': case 'd':
|
|
||||||
base = 10;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// binary
|
|
||||||
case 'B':
|
|
||||||
pre = "0B";
|
|
||||||
base = 2;
|
|
||||||
break;
|
|
||||||
case 'b':
|
|
||||||
pre = "0b";
|
|
||||||
base = 2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// octal
|
|
||||||
case 'o':
|
|
||||||
pre = "0";
|
|
||||||
base = 8;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// hex
|
|
||||||
case 'X':
|
|
||||||
digits = highdigits;
|
|
||||||
pre = "0X";
|
|
||||||
base = 16;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'x':
|
|
||||||
pre = "0x";
|
|
||||||
base = 16;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
digit = toupper(digit);
|
||||||
// parse int
|
}
|
||||||
while (x != 0) {
|
|
||||||
res = digits[x % base] + res;
|
|
||||||
x /= base;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle 0
|
const bool has_sign = (x < 0 or fmt.sign != '-');
|
||||||
if (res.empty()) {
|
const bool zero = fmt.fill == '0';
|
||||||
res = '0' + res;
|
const size_t prefix = fmt.alt ? (fmt.type == 'd' ? 0 : 2 - (fmt.type == 'o')) : 0;
|
||||||
}
|
const size_t sgnlen = len + (zero ? has_sign + prefix : 0);
|
||||||
|
const size_t explen = fennec::max(sgnlen, fmt.width) + (zero ? 0 : has_sign + prefix);
|
||||||
|
const size_t fill = fmt.width > sgnlen ? fmt.width - sgnlen : 0;
|
||||||
|
size_t sign = 0;
|
||||||
|
|
||||||
// add prefix unless fill is '0'
|
string res = string(explen);
|
||||||
if (fmt.alt and fmt.fill != '0' and (base != 8 or res[0] != '0')) {
|
|
||||||
res = pre + res;
|
|
||||||
}
|
|
||||||
|
|
||||||
// fill
|
if (fill > 0) {
|
||||||
size_t fill = fmt.alt ? fmt.width - pre.length() : fmt.width;
|
|
||||||
switch (fmt.align) {
|
switch (fmt.align) {
|
||||||
// align left
|
|
||||||
case '<':
|
case '<':
|
||||||
while (res.size() < fill) {
|
memcpy(res.data() + has_sign + prefix, digits, len);
|
||||||
res += fmt.fill == '0' ? ' ' : fmt.fill;
|
memset(res.data() + has_sign + prefix + len, fmt.fill == '0' ? ' ' : fmt.fill, fill);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
case '>': case '\0':
|
||||||
// align right
|
memcpy(res.data() + explen - len, digits, len);
|
||||||
case '>': default:
|
sign = fmt.fill == '0' ? 0 : explen - len - 1 - prefix;
|
||||||
while (res.size() < fill) {
|
memset(res.data(), fmt.fill, explen - len);
|
||||||
res = fmt.fill + res;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// align
|
|
||||||
case '^':
|
case '^':
|
||||||
bool rr = true;
|
size_t bef = fill / 2 + has_sign + prefix;
|
||||||
while (res.size() < fill) {
|
size_t aft = explen - bef;
|
||||||
if (rr) {
|
memcpy(res.data() + bef, digits, len);
|
||||||
res += fmt.fill == '0' ? ' ' : fmt.fill;
|
sign = fmt.fill == '0' ? 0 : bef - 1 - prefix;
|
||||||
|
memset(res.data(), fmt.fill, bef);
|
||||||
|
memset(res.data() + bef + len, fmt.fill == '0' ? ' ' : fmt.fill, aft);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
res = fmt.fill + res;
|
memcpy(res.data() + has_sign + prefix, digits, len);
|
||||||
}
|
|
||||||
rr = !rr;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// add prefix after filled 0s
|
if (has_sign) {
|
||||||
if (fmt.alt and fmt.fill == '0') {
|
res[sign] = (x < 0) ? '-' : fmt.sign;
|
||||||
res = pre + res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// add sign
|
if (prefix) {
|
||||||
switch (fmt.sign) {
|
res[sign + has_sign] = '0';
|
||||||
case '+':
|
if (fmt.type != 'o') {
|
||||||
res = (neg ? '-' : '+') + res;
|
res[sign + has_sign + 1] = fmt.type;
|
||||||
break;
|
}
|
||||||
case ' ':
|
|
||||||
res = (neg ? '-' : ' ') + res;
|
|
||||||
break;
|
|
||||||
case '-': default:
|
|
||||||
if (neg) res = '-' + res;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@@ -206,6 +158,22 @@ struct formatter<BoolT> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename FloatT> requires(is_floating_point_v<FloatT>)
|
||||||
|
struct formatter<FloatT> {
|
||||||
|
string operator()(const format_arg& fmt, FloatT x) {
|
||||||
|
|
||||||
|
// nan & inf cases
|
||||||
|
if (isnan(x)) {
|
||||||
|
return string("nan");
|
||||||
|
}
|
||||||
|
if (isinf(x)) {
|
||||||
|
return string("inf");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // FENNEC_FORMAT_FORMATTER_H
|
#endif // FENNEC_FORMAT_FORMATTER_H
|
||||||
@@ -440,7 +440,10 @@ public:
|
|||||||
///
|
///
|
||||||
/// \brief Default Destructor, releases the memory block if still present
|
/// \brief Default Destructor, releases the memory block if still present
|
||||||
constexpr ~allocation() noexcept {
|
constexpr ~allocation() noexcept {
|
||||||
if (_data) _alloc.deallocate(_data);
|
if (_data) {
|
||||||
|
_alloc.deallocate(_data);
|
||||||
|
_data = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
147
source/format/charconv.cpp
Normal file
147
source/format/charconv.cpp
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file charconv.h
|
||||||
|
/// \brief
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#define __cpp_lib_to_chars
|
||||||
|
#include <charconv>
|
||||||
|
#include <system_error>
|
||||||
|
#include <fennec/format/charconv.h>
|
||||||
|
#include <fennec/lang/assert.h>
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
char* to_chars(char* first, char* last, char x, int base) {
|
||||||
|
auto res = std::to_chars(first, last, x, base);
|
||||||
|
assertf(res.ec == std::errc(), std::make_error_code(res.ec).message().c_str());
|
||||||
|
return res.ptr;
|
||||||
|
}
|
||||||
|
char* to_chars(char* first, char* last, signed char x, int base) {
|
||||||
|
auto res = std::to_chars(first, last, x, base);
|
||||||
|
assertf(res.ec == std::errc(), std::make_error_code(res.ec).message().c_str());
|
||||||
|
return res.ptr;
|
||||||
|
}
|
||||||
|
char* to_chars(char* first, char* last, unsigned char x, int base) {
|
||||||
|
auto res = std::to_chars(first, last, x, base);
|
||||||
|
assertf(res.ec == std::errc(), std::make_error_code(res.ec).message().c_str());
|
||||||
|
return res.ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* to_chars(char* first, char* last, signed short x, int base) {
|
||||||
|
auto res = std::to_chars(first, last, x, base);
|
||||||
|
assertf(res.ec == std::errc(), std::make_error_code(res.ec).message().c_str());
|
||||||
|
return res.ptr;
|
||||||
|
}
|
||||||
|
char* to_chars(char* first, char* last, unsigned short x, int base) {
|
||||||
|
auto res = std::to_chars(first, last, x, base);
|
||||||
|
assertf(res.ec == std::errc(), std::make_error_code(res.ec).message().c_str());
|
||||||
|
return res.ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* to_chars(char* first, char* last, signed int x, int base) {
|
||||||
|
auto res = std::to_chars(first, last, x, base);
|
||||||
|
assertf(res.ec == std::errc(), std::make_error_code(res.ec).message().c_str());
|
||||||
|
return res.ptr;
|
||||||
|
}
|
||||||
|
char* to_chars(char* first, char* last, unsigned int x, int base) {
|
||||||
|
auto res = std::to_chars(first, last, x, base);
|
||||||
|
assertf(res.ec == std::errc(), std::make_error_code(res.ec).message().c_str());
|
||||||
|
return res.ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* to_chars(char* first, char* last, signed long x, int base) {
|
||||||
|
auto res = std::to_chars(first, last, x, base);
|
||||||
|
assertf(res.ec == std::errc(), std::make_error_code(res.ec).message().c_str());
|
||||||
|
return res.ptr;
|
||||||
|
}
|
||||||
|
char* to_chars(char* first, char* last, unsigned long x, int base) {
|
||||||
|
auto res = std::to_chars(first, last, x, base);
|
||||||
|
assertf(res.ec == std::errc(), std::make_error_code(res.ec).message().c_str());
|
||||||
|
return res.ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* to_chars(char* first, char* last, signed long long x, int base) {
|
||||||
|
auto res = std::to_chars(first, last, x, base);
|
||||||
|
assertf(res.ec == std::errc(), std::make_error_code(res.ec).message().c_str());
|
||||||
|
return res.ptr;
|
||||||
|
}
|
||||||
|
char* to_chars(char* first, char* last, unsigned long long x, int base) {
|
||||||
|
auto res = std::to_chars(first, last, x, base);
|
||||||
|
assertf(res.ec == std::errc(), std::make_error_code(res.ec).message().c_str());
|
||||||
|
return res.ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::chars_format ctofmt(char c) {
|
||||||
|
switch (c) {
|
||||||
|
default: return std::chars_format::general;
|
||||||
|
case 'a': case 'A': return std::chars_format::hex;
|
||||||
|
case 'f': case 'F': return std::chars_format::fixed;
|
||||||
|
case 'e': case 'E': return std::chars_format::scientific;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char* to_chars(char* first, char* last, float x) {
|
||||||
|
auto res = std::to_chars(first, last, x);
|
||||||
|
assertf(res.ec == std::errc(), std::make_error_code(res.ec).message().c_str());
|
||||||
|
return res.ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* to_chars(char* first, char* last, float x, char fmt) {
|
||||||
|
auto res = std::to_chars(first, last, x, ctofmt(fmt));
|
||||||
|
assertf(res.ec == std::errc(), std::make_error_code(res.ec).message().c_str());
|
||||||
|
return res.ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* to_chars(char* first, char* last, float x, char fmt, int precision) {
|
||||||
|
auto res = std::to_chars(first, last, x, ctofmt(fmt), precision);
|
||||||
|
assertf(res.ec == std::errc(), std::make_error_code(res.ec).message().c_str());
|
||||||
|
return res.ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char* to_chars(char* first, char* last, double x) {
|
||||||
|
auto res = std::to_chars(first, last, x);
|
||||||
|
assertf(res.ec == std::errc(), std::make_error_code(res.ec).message().c_str());
|
||||||
|
return res.ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* to_chars(char* first, char* last, double x, char fmt) {
|
||||||
|
auto res = std::to_chars(first, last, x, ctofmt(fmt));
|
||||||
|
assertf(res.ec == std::errc(), std::make_error_code(res.ec).message().c_str());
|
||||||
|
return res.ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* to_chars(char* first, char* last, double x, char fmt, int precision) {
|
||||||
|
auto res = std::to_chars(first, last, x, ctofmt(fmt), precision);
|
||||||
|
assertf(res.ec == std::errc(), std::make_error_code(res.ec).message().c_str());
|
||||||
|
return res.ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -72,6 +72,15 @@ inline void fennec_test_format() {
|
|||||||
|
|
||||||
fennec_test_spacer(1);
|
fennec_test_spacer(1);
|
||||||
|
|
||||||
|
fennec_test_run(fennec::format("{:#06d}", -15), string("-00015"));
|
||||||
|
fennec_test_run(fennec::format("{:#06x}", -15), string("-0x00f"));
|
||||||
|
fennec_test_run(fennec::format("{:#06X}", -15), string("-0X00F"));
|
||||||
|
fennec_test_run(fennec::format("{:#06o}", -15), string("-00017"));
|
||||||
|
fennec_test_run(fennec::format("{:#06b}", -15), string("-0b1111"));
|
||||||
|
fennec_test_run(fennec::format("{:#06B}", -15), string("-0B1111"));
|
||||||
|
|
||||||
|
fennec_test_spacer(1);
|
||||||
|
|
||||||
fennec_test_run(fennec::format("{},{}", true, false), string("true,false"));
|
fennec_test_run(fennec::format("{},{}", true, false), string("true,false"));
|
||||||
fennec_test_run(fennec::format("{:#06b},{:#06b}", true, false), string("0b0001,0b0000"));
|
fennec_test_run(fennec::format("{:#06b},{:#06b}", true, false), string("0b0001,0b0000"));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user