Просмотр исходного кода

vsnprintf: Implemented length sub-specifier.

Branimir Karadžić 8 лет назад
Родитель
Сommit
3930149a77
4 измененных файлов с 173 добавлено и 6 удалено
  1. 6 0
      include/bx/string.h
  2. 93 6
      src/crt.cpp
  3. 61 0
      src/dtoa.cpp
  4. 13 0
      tests/vsnprintf_test.cpp

+ 6 - 0
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);
 

+ 93 - 6
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:

+ 61 - 0
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

+ 13 - 0
tests/vsnprintf_test.cpp

@@ -5,6 +5,7 @@
 
 #include "test.h"
 #include <bx/string.h>
+#include <inttypes.h>
 
 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", "")