Skip to content

Commit f5c797a

Browse files
committed
vsnprintf now can take StringView as argument.
1 parent 70f998b commit f5c797a

File tree

5 files changed

+132
-26
lines changed

5 files changed

+132
-26
lines changed

include/bx/inline/string.inl

+36-12
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ namespace bx
124124
{
125125
m_len = INT32_MAX == _len ? strLen(_ptr) : _len;
126126
m_ptr = _ptr;
127+
m_0terminated = INT32_MAX == _len;
127128
}
128129
}
129130

@@ -149,6 +150,7 @@ namespace bx
149150
{
150151
m_ptr = "";
151152
m_len = 0;
153+
m_0terminated = true;
152154
}
153155

154156
inline const char* StringView::getPtr() const
@@ -171,36 +173,46 @@ namespace bx
171173
return m_len;
172174
}
173175

176+
inline bool StringView::is0Terminated() const
177+
{
178+
return m_0terminated;
179+
}
180+
174181
template<bx::AllocatorI** AllocatorT>
175182
inline StringT<AllocatorT>::StringT()
176183
: StringView()
184+
, m_capacity(0)
177185
{
186+
clear();
178187
}
179188

180189
template<bx::AllocatorI** AllocatorT>
181190
inline StringT<AllocatorT>::StringT(const StringT<AllocatorT>& _rhs)
182191
: StringView()
192+
, m_capacity(0)
183193
{
184194
set(_rhs);
185195
}
186196

187197
template<bx::AllocatorI** AllocatorT>
188-
inline StringT<AllocatorT>& StringT<AllocatorT>::operator=(const StringT<AllocatorT>& _rhs)
198+
inline StringT<AllocatorT>::StringT(const StringView& _rhs)
199+
: StringView()
200+
, m_capacity(0)
189201
{
190202
set(_rhs);
191-
return *this;
192203
}
193204

194205
template<bx::AllocatorI** AllocatorT>
195-
inline StringT<AllocatorT>::StringT(const StringView& _rhs)
206+
inline StringT<AllocatorT>::~StringT()
196207
{
197-
set(_rhs);
208+
clear();
198209
}
199210

200211
template<bx::AllocatorI** AllocatorT>
201-
inline StringT<AllocatorT>::~StringT()
212+
inline StringT<AllocatorT>& StringT<AllocatorT>::operator=(const StringT<AllocatorT>& _rhs)
202213
{
203-
clear();
214+
set(_rhs);
215+
return *this;
204216
}
205217

206218
template<bx::AllocatorI** AllocatorT>
@@ -215,13 +227,22 @@ namespace bx
215227
{
216228
if (0 != _str.getLength() )
217229
{
218-
int32_t old = m_len;
219-
int32_t len = m_len + strLen(_str);
220-
char* ptr = (char*)BX_REALLOC(*AllocatorT, 0 != m_len ? const_cast<char*>(m_ptr) : NULL, len+1);
230+
const int32_t old = m_len;
231+
const int32_t len = m_len + _str.getLength();
232+
233+
char* ptr = const_cast<char*>(m_ptr);
234+
235+
if (len+1 > m_capacity)
236+
{
237+
const int32_t capacity = alignUp(len+1, 256);
238+
ptr = (char*)BX_REALLOC(*AllocatorT, 0 != m_capacity ? ptr : NULL, capacity);
239+
240+
*const_cast<char**>(&m_ptr) = ptr;
241+
m_capacity = capacity;
242+
}
243+
221244
m_len = len;
222245
strCopy(ptr + old, len-old+1, _str);
223-
224-
*const_cast<char**>(&m_ptr) = ptr;
225246
}
226247
}
227248

@@ -234,11 +255,14 @@ namespace bx
234255
template<bx::AllocatorI** AllocatorT>
235256
inline void StringT<AllocatorT>::clear()
236257
{
237-
if (0 != m_len)
258+
m_0terminated = true;
259+
260+
if (0 != m_capacity)
238261
{
239262
BX_FREE(*AllocatorT, const_cast<char*>(m_ptr) );
240263

241264
StringView::clear();
265+
m_capacity = 0;
242266
}
243267
}
244268

include/bx/string.h

+12-5
Original file line numberDiff line numberDiff line change
@@ -91,15 +91,19 @@ namespace bx
9191
///
9292
const char* getTerm() const;
9393

94-
///
94+
/// Returns `true` if string is empty.
9595
bool isEmpty() const;
9696

97-
///
97+
/// Returns string length.
9898
int32_t getLength() const;
9999

100+
/// Returns `true` if string is zero terminated.
101+
bool is0Terminated() const;
102+
100103
protected:
101104
const char* m_ptr;
102105
int32_t m_len;
106+
bool m_0terminated;
103107
};
104108

105109
/// ASCII string
@@ -113,15 +117,15 @@ namespace bx
113117
///
114118
StringT(const StringT<AllocatorT>& _rhs);
115119

116-
///
117-
StringT<AllocatorT>& operator=(const StringT<AllocatorT>& _rhs);
118-
119120
///
120121
StringT(const StringView& _rhs);
121122

122123
///
123124
~StringT();
124125

126+
///
127+
StringT<AllocatorT>& operator=(const StringT<AllocatorT>& _rhs);
128+
125129
///
126130
void set(const StringView& _str);
127131

@@ -137,6 +141,9 @@ namespace bx
137141
/// Returns zero-terminated C string pointer.
138142
///
139143
const char* getCPtr() const;
144+
145+
protected:
146+
int32_t m_capacity;
140147
};
141148

142149
/// Retruns true if character is part of space set.

src/string.cpp

+37-9
Original file line numberDiff line numberDiff line change
@@ -813,6 +813,11 @@ namespace bx
813813
return write(_writer, _str, _param.prec, _param, _err);
814814
}
815815

816+
static int32_t write(WriterI* _writer, const StringView& _str, const Param& _param, Error* _err)
817+
{
818+
return write(_writer, _str.getPtr(), min(_param.prec, _str.getLength() ), _param, _err);
819+
}
820+
816821
static int32_t write(WriterI* _writer, int32_t _i, const Param& _param, Error* _err)
817822
{
818823
char str[33];
@@ -939,12 +944,15 @@ namespace bx
939944
}
940945
else if ('%' == ch)
941946
{
942-
// %[flags][width][.precision][length sub-specifier]specifier
947+
// %[Flags][Width][.Precision][Leegth]Type
943948
read(&reader, ch, &err);
944949

945950
Param param;
946951

947-
// flags
952+
// Reference(s):
953+
// - Flags field
954+
// https://en.wikipedia.org/wiki/Printf_format_string#Flags_field
955+
//
948956
while (err.isOk()
949957
&& ( ' ' == ch
950958
|| '-' == ch
@@ -971,7 +979,10 @@ namespace bx
971979
param.fill = ' ';
972980
}
973981

974-
// width
982+
// Reference(s):
983+
// - Width field
984+
// https://en.wikipedia.org/wiki/Printf_format_string#Width_field
985+
//
975986
if ('*' == ch)
976987
{
977988
read(&reader, ch, &err);
@@ -994,7 +1005,9 @@ namespace bx
9941005
}
9951006
}
9961007

997-
// .precision
1008+
// Reference(s):
1009+
// - Precision field
1010+
// https://en.wikipedia.org/wiki/Printf_format_string#Precision_field
9981011
if ('.' == ch)
9991012
{
10001013
read(&reader, ch, &err);
@@ -1016,7 +1029,9 @@ namespace bx
10161029
}
10171030
}
10181031

1019-
// length sub-specifier
1032+
// Reference(s):
1033+
// - Length field
1034+
// https://en.wikipedia.org/wiki/Printf_format_string#Length_field
10201035
while (err.isOk()
10211036
&& ( 'h' == ch
10221037
|| 'I' == ch
@@ -1031,8 +1046,8 @@ namespace bx
10311046
default: break;
10321047

10331048
case 'j': param.bits = sizeof(intmax_t )*8; break;
1034-
case 't': param.bits = sizeof(size_t )*8; break;
1035-
case 'z': param.bits = sizeof(ptrdiff_t)*8; break;
1049+
case 't': param.bits = sizeof(ptrdiff_t)*8; break;
1050+
case 'z': param.bits = sizeof(size_t )*8; break;
10361051

10371052
case 'h': case 'I': case 'l':
10381053
switch (ch)
@@ -1071,15 +1086,24 @@ namespace bx
10711086
break;
10721087
}
10731088

1074-
// specifier
1089+
// Reference(s):
1090+
// - Type field
1091+
// https://en.wikipedia.org/wiki/Printf_format_string#Type_field
10751092
switch (toLower(ch) )
10761093
{
10771094
case 'c':
10781095
size += write(_writer, char(va_arg(_argList, int32_t) ), param, _err);
10791096
break;
10801097

10811098
case 's':
1082-
size += write(_writer, va_arg(_argList, const char*), param, _err);
1099+
if (isUpper(ch) )
1100+
{
1101+
size += write(_writer, va_arg(_argList, const StringView), param, _err);
1102+
}
1103+
else
1104+
{
1105+
size += write(_writer, va_arg(_argList, const char*), param, _err);
1106+
}
10831107
break;
10841108

10851109
case 'o':
@@ -1131,6 +1155,10 @@ namespace bx
11311155
}
11321156
break;
11331157

1158+
case 'n':
1159+
*va_arg(_argList, int32_t*) = size;
1160+
break;
1161+
11341162
default:
11351163
size += write(_writer, ch, _err);
11361164
break;

tests/string_test.cpp

+26
Original file line numberDiff line numberDiff line change
@@ -555,3 +555,29 @@ TEST_CASE("suffix", "")
555555
REQUIRE(0 == bx::strCmp(bx::strTrimSuffix("abvgd-1389.0", "389.0"), "abvgd-1") );
556556
REQUIRE(0 == bx::strCmp(bx::strTrimSuffix("abvgd-1389.0", "xyz"), "abvgd-1389.0") );
557557
}
558+
559+
TEST_CASE("0terminated", "")
560+
{
561+
const bx::StringView t0("1389");
562+
REQUIRE(t0.is0Terminated() );
563+
const bx::StringView t1(strTrimPrefix(t0, "13") );
564+
REQUIRE(!t1.is0Terminated() );
565+
const bx::StringView t2(strTrimSuffix(t0, "89") );
566+
REQUIRE(!t2.is0Terminated() );
567+
568+
bx::DefaultAllocator crt;
569+
g_allocator = &crt;
570+
571+
typedef bx::StringT<&g_allocator> String;
572+
573+
String st;
574+
REQUIRE(st.is0Terminated() );
575+
576+
st = strTrimPrefix(t0, "13");
577+
REQUIRE(2 == st.getLength() );
578+
REQUIRE(st.is0Terminated() );
579+
580+
st = strTrimSuffix(t0, "89");
581+
REQUIRE(2 == st.getLength() );
582+
REQUIRE(st.is0Terminated() );
583+
}

tests/vsnprintf_test.cpp

+21
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,22 @@ TEST_CASE("vsnprintf t")
184184
size_t size = -1;
185185

186186
REQUIRE(test("-1", "%td", size) );
187+
188+
REQUIRE(test("3221225472", "%td", size_t(3221225472) ) );
189+
}
190+
191+
TEST_CASE("vsnprintf n")
192+
{
193+
char temp[64];
194+
195+
int32_t p0, p1, p2;
196+
bx::snprintf(temp, sizeof(temp), "%n", &p0);
197+
REQUIRE(0 == p0);
198+
199+
bx::snprintf(temp, sizeof(temp), "01%n23%n45%n", &p0, &p1, &p2);
200+
REQUIRE(2 == p0);
201+
REQUIRE(4 == p1);
202+
REQUIRE(6 == p2);
187203
}
188204

189205
TEST_CASE("vsnprintf g")
@@ -215,6 +231,11 @@ TEST_CASE("vsnprintf")
215231
, hello.getLength(), hello.getPtr()
216232
, world.getLength(), world.getPtr()
217233
) );
234+
235+
REQUIRE(test("hello, world!", "%S, %S!"
236+
, hello
237+
, world
238+
) );
218239
}
219240

220241
TEST_CASE("vsnprintf write")

0 commit comments

Comments
 (0)