From 3930149a77f71668fae22e7185240064e6d70a0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Branimir=20Karad=C5=BEi=C4=87?= Date: Sat, 11 Feb 2017 21:08:56 -0800 Subject: [PATCH] vsnprintf: Implemented length sub-specifier. --- include/bx/string.h | 6 +++ src/crt.cpp | 99 +++++++++++++++++++++++++++++++++++++--- src/dtoa.cpp | 61 +++++++++++++++++++++++++ tests/vsnprintf_test.cpp | 13 ++++++ 4 files changed, 173 insertions(+), 6 deletions(-) diff --git a/include/bx/string.h b/include/bx/string.h index 9236c7e..7789fc8 100644 --- a/include/bx/string.h +++ b/include/bx/string.h @@ -223,9 +223,15 @@ namespace bx /// int32_t toString(char* _out, size_t _max, int32_t _value, uint32_t _base = 10); + /// + int32_t toString(char* _out, size_t _max, int64_t _value, uint32_t _base = 10); + /// int32_t toString(char* _out, size_t _max, uint32_t _value, uint32_t _base = 10); + /// + int32_t toString(char* _out, size_t _max, uint64_t _value, uint32_t _base = 10); + /// uint32_t hashMurmur2A(const StringView& _data); diff --git a/src/crt.cpp b/src/crt.cpp index 58ab014..73b616a 100644 --- a/src/crt.cpp +++ b/src/crt.cpp @@ -153,6 +153,7 @@ namespace bx , base(10) , prec(6) , fill(' ') + , bits(0) , left(false) , upper(false) , spec(false) @@ -164,6 +165,7 @@ namespace bx uint32_t base; uint32_t prec; char fill; + uint8_t bits; bool left; bool upper; bool spec; @@ -235,7 +237,7 @@ namespace bx return write(_writer, str, len, _param, _err); } - static int32_t write(WriterI* _writer, uint32_t _i, const Param& _param, Error* _err) + static int32_t write(WriterI* _writer, int64_t _i, const Param& _param, Error* _err) { char str[33]; int32_t len = toString(str, sizeof(str), _i, _param.base); @@ -248,6 +250,32 @@ namespace bx return write(_writer, str, len, _param, _err); } + static int32_t write(WriterI* _writer, uint32_t _u, const Param& _param, Error* _err) + { + char str[33]; + int32_t len = toString(str, sizeof(str), _u, _param.base); + + if (len == 0) + { + return 0; + } + + return write(_writer, str, len, _param, _err); + } + + static int32_t write(WriterI* _writer, uint64_t _u, const Param& _param, Error* _err) + { + char str[33]; + int32_t len = toString(str, sizeof(str), _u, _param.base); + + if (len == 0) + { + return 0; + } + + return write(_writer, str, len, _param, _err); + } + static int32_t write(WriterI* _writer, double _d, const Param& _param, Error* _err) { char str[1024]; @@ -323,9 +351,10 @@ namespace bx { switch (ch) { + default: + case ' ': param.fill = ' '; break; case '-': param.left = true; break; case '+': param.sign = true; break; - case ' ': param.fill = ' '; break; case '0': param.fill = '0'; break; case '#': param.spec = true; break; } @@ -379,6 +408,48 @@ namespace bx } } + // length sub-specifier + while ('h' == ch + || 'I' == ch + || 'l' == ch + || 'j' == ch + || 't' == ch + || 'z' == ch) + { + switch (ch) + { + default: break; + + case 'j': param.bits = sizeof(intmax_t )*8; break; + case 't': param.bits = sizeof(size_t )*8; break; + case 'z': param.bits = sizeof(ptrdiff_t)*8; break; + + case 'h': case 'I': case 'l': + switch (ch) + { + case 'h': param.bits = sizeof(short int)*8; break; + case 'l': param.bits = sizeof(long int )*8; break; + default: break; + } + + read(&reader, ch); + switch (ch) + { + case 'h': param.bits = sizeof(signed char )*8; break; + case 'l': param.bits = sizeof(long long int)*8; break; + case '6': + read(&reader, ch); + if ('4' == ch) { param.bits = sizeof(int64_t)*8; } + break; + + default: seek(&reader, -1); break; + } + break; + } + + read(&reader, ch); + } + switch (toLower(ch) ) { case 'c': @@ -391,13 +462,21 @@ namespace bx case 'o': param.base = 8; - size += write(_writer, va_arg(_argList, int32_t), param, _err); + switch (param.bits) + { + default: size += write(_writer, va_arg(_argList, int32_t), param, _err); break; + case 64: size += write(_writer, va_arg(_argList, int64_t), param, _err); break; + } break; case 'i': case 'd': param.base = 10; - size += write(_writer, va_arg(_argList, int32_t), param, _err); + switch (param.bits) + { + default: size += write(_writer, va_arg(_argList, int32_t), param, _err); break; + case 64: size += write(_writer, va_arg(_argList, int64_t), param, _err); break; + }; break; case 'f': @@ -411,12 +490,20 @@ namespace bx case 'x': param.base = 16; param.upper = isUpper(ch); - size += write(_writer, va_arg(_argList, uint32_t), param, _err); + switch (param.bits) + { + default: size += write(_writer, va_arg(_argList, uint32_t), param, _err); break; + case 64: size += write(_writer, va_arg(_argList, uint64_t), param, _err); break; + } break; case 'u': param.base = 10; - size += write(_writer, va_arg(_argList, uint32_t), param, _err); + switch (param.bits) + { + default: size += write(_writer, va_arg(_argList, uint32_t), param, _err); break; + case 64: size += write(_writer, va_arg(_argList, uint64_t), param, _err); break; + } break; default: diff --git a/src/dtoa.cpp b/src/dtoa.cpp index b3f9d22..dfdd61d 100644 --- a/src/dtoa.cpp +++ b/src/dtoa.cpp @@ -487,6 +487,29 @@ namespace bx return toString(_dst, _max, uint32_t(_value), _base); } + int32_t toString(char* _dst, size_t _max, int64_t _value, uint32_t _base) + { + if (_base == 10 + && _value < 0) + { + if (_max < 1) + { + return 0; + } + + _max = toString(_dst + 1, _max - 1, uint64_t(-_value), _base); + if (_max == 0) + { + return 0; + } + + *_dst = '-'; + return int32_t(_max + 1); + } + + return toString(_dst, _max, uint64_t(_value), _base); + } + int32_t toString(char* _dst, size_t _max, uint32_t _value, uint32_t _base) { char data[32]; @@ -525,4 +548,42 @@ namespace bx return int32_t(len); } + int32_t toString(char* _dst, size_t _max, uint64_t _value, uint32_t _base) + { + char data[32]; + size_t len = 0; + + if (_base > 16 + || _base < 2) + { + return 0; + } + + do + { + const uint64_t rem = _value % _base; + _value /= _base; + if (rem < 10) + { + data[len++] = char('0' + rem); + } + else + { + data[len++] = char('a' + rem - 10); + } + + } while (_value != 0); + + if (_max < len + 1) + { + return 0; + } + + reverse(data, len); + + memCopy(_dst, data, len); + _dst[len] = '\0'; + return int32_t(len); + } + } // namespace bx diff --git a/tests/vsnprintf_test.cpp b/tests/vsnprintf_test.cpp index 72d7109..cf524d0 100644 --- a/tests/vsnprintf_test.cpp +++ b/tests/vsnprintf_test.cpp @@ -5,6 +5,7 @@ #include "test.h" #include +#include TEST_CASE("vsnprintf NULL buffer", "No output buffer provided.") { @@ -81,6 +82,18 @@ TEST_CASE("vsnprintf d/i/o/u/x", "") REQUIRE(test("0000000000001234ABCD", "%020X", 0x1234abcd) ); REQUIRE(test("000000000000edcb5433", "%020x", -0x1234abcd) ); REQUIRE(test("000000000000EDCB5433", "%020X", -0x1234abcd) ); + + if (BX_ENABLED(BX_ARCH_32BIT) ) + { + REQUIRE(test("2147483647", "%jd", INTMAX_MAX) ); + } + else + { + REQUIRE(test("9223372036854775807", "%jd", INTMAX_MAX) ); + } + + REQUIRE(test("18446744073709551615", "%" PRIu64, UINT64_MAX) ); + REQUIRE(test("ffffffffffffffff", "%016" PRIx64, UINT64_MAX) ); } TEST_CASE("vsnprintf modifiers", "")