Skip to content

Commit 01a87ef

Browse files
committed
Add basic_string::__resize_default_init (from P1072)
This patch adds an implementation of __resize_default_init as described in P1072R2. Additionally, it uses it in filesystem to demonstrate its intended utility. Once P1072 lands, or if it changes it's interface, I will adjust the internal libc++ implementation to match. llvm-svn: 347589
1 parent e8e8c5c commit 01a87ef

File tree

3 files changed

+116
-12
lines changed

3 files changed

+116
-12
lines changed

libcxx/include/string

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -956,6 +956,8 @@ public:
956956
void resize(size_type __n, value_type __c);
957957
_LIBCPP_INLINE_VISIBILITY void resize(size_type __n) {resize(__n, value_type());}
958958

959+
_LIBCPP_INLINE_VISIBILITY void __resize_default_init(size_type __n);
960+
959961
void reserve(size_type __res_arg = 0);
960962
_LIBCPP_INLINE_VISIBILITY
961963
void shrink_to_fit() _NOEXCEPT {reserve();}
@@ -1010,6 +1012,10 @@ public:
10101012
basic_string& append(const value_type* __s, size_type __n);
10111013
basic_string& append(const value_type* __s);
10121014
basic_string& append(size_type __n, value_type __c);
1015+
1016+
_LIBCPP_INLINE_VISIBILITY
1017+
void __append_default_init(size_type __n);
1018+
10131019
template <class _ForwardIterator>
10141020
_LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
10151021
basic_string& __append_forward_unsafe(_ForwardIterator, _ForwardIterator);
@@ -2427,6 +2433,23 @@ basic_string<_CharT, _Traits, _Allocator>::append(size_type __n, value_type __c)
24272433
return *this;
24282434
}
24292435

2436+
template <class _CharT, class _Traits, class _Allocator>
2437+
inline void
2438+
basic_string<_CharT, _Traits, _Allocator>::__append_default_init(size_type __n)
2439+
{
2440+
if (__n)
2441+
{
2442+
size_type __cap = capacity();
2443+
size_type __sz = size();
2444+
if (__cap - __sz < __n)
2445+
__grow_by(__cap, __sz + __n - __cap, __sz, __sz, 0);
2446+
pointer __p = __get_pointer();
2447+
__sz += __n;
2448+
__set_size(__sz);
2449+
traits_type::assign(__p[__sz], value_type());
2450+
}
2451+
}
2452+
24302453
template <class _CharT, class _Traits, class _Allocator>
24312454
void
24322455
basic_string<_CharT, _Traits, _Allocator>::push_back(value_type __c)
@@ -3082,6 +3105,17 @@ basic_string<_CharT, _Traits, _Allocator>::resize(size_type __n, value_type __c)
30823105
__erase_to_end(__n);
30833106
}
30843107

3108+
template <class _CharT, class _Traits, class _Allocator>
3109+
inline void
3110+
basic_string<_CharT, _Traits, _Allocator>::__resize_default_init(size_type __n)
3111+
{
3112+
size_type __sz = size();
3113+
if (__n > __sz) {
3114+
__append_default_init(__n - __sz);
3115+
} else
3116+
__erase_to_end(__n);
3117+
}
3118+
30853119
template <class _CharT, class _Traits, class _Allocator>
30863120
inline _LIBCPP_INLINE_VISIBILITY
30873121
typename basic_string<_CharT, _Traits, _Allocator>::size_type

libcxx/src/filesystem/filesystem_common.h

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -67,24 +67,31 @@ static string format_string_imp(const char* msg, ...) {
6767
va_copy(args_cp, args);
6868
GuardVAList args_copy_guard(args_cp);
6969

70+
std::string result;
71+
7072
array<char, 256> local_buff;
71-
size_t size = local_buff.size();
72-
auto ret = ::vsnprintf(local_buff.data(), size, msg, args_cp);
73+
size_t size_with_null = local_buff.size();
74+
auto ret = ::vsnprintf(local_buff.data(), size_with_null, msg, args_cp);
7375

7476
args_copy_guard.clear();
7577

7678
// handle empty expansion
7779
if (ret == 0)
78-
return string{};
79-
if (static_cast<size_t>(ret) < size)
80-
return string(local_buff.data());
81-
82-
// we did not provide a long enough buffer on our first attempt.
83-
// add 1 to size to account for null-byte in size cast to prevent overflow
84-
size = static_cast<size_t>(ret) + 1;
85-
auto buff_ptr = unique_ptr<char[]>(new char[size]);
86-
ret = ::vsnprintf(buff_ptr.get(), size, msg, args);
87-
return string(buff_ptr.get());
80+
return result;
81+
if (static_cast<size_t>(ret) < size_with_null) {
82+
result.assign(local_buff.data(), static_cast<size_t>(ret));
83+
return result;
84+
}
85+
86+
// we did not provide a long enough buffer on our first attempt. The
87+
// return value is the number of bytes (excluding the null byte) that are
88+
// needed for formatting.
89+
size_with_null = static_cast<size_t>(ret) + 1;
90+
result.__resize_default_init(size_with_null - 1);
91+
ret = ::vsnprintf(&result[0], size_with_null, msg, args);
92+
_LIBCPP_ASSERT(static_cast<size_t>(ret) == (size_with_null - 1), "TODO");
93+
94+
return result;
8895
}
8996

9097
const char* unwrap(string const& s) { return s.c_str(); }
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is dual licensed under the MIT and the University of Illinois Open
6+
// Source Licenses. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
// <string>
11+
12+
// __resize_default_init(size_type)
13+
14+
#include <string>
15+
#include <cassert>
16+
17+
#include "test_macros.h"
18+
19+
void write_c_str(char *buf, int size) {
20+
for (int i=0; i < size; ++i) {
21+
buf[i] = 'a';
22+
}
23+
buf[size] = '\0';
24+
}
25+
26+
void test_buffer_usage()
27+
{
28+
{
29+
unsigned buff_size = 125;
30+
unsigned used_size = buff_size - 16;
31+
std::string s;
32+
s.__resize_default_init(buff_size);
33+
write_c_str(&s[0], used_size);
34+
assert(s.size() == buff_size);
35+
assert(strlen(s.data()) == used_size);
36+
s.__resize_default_init(used_size);
37+
assert(s.size() == used_size);
38+
assert(s.data()[used_size] == '\0');
39+
for (unsigned i=0; i < used_size; ++i) {
40+
assert(s[i] == 'a');
41+
}
42+
}
43+
}
44+
45+
void test_basic() {
46+
{
47+
std::string s;
48+
s.__resize_default_init(3);
49+
assert(s.size() == 3);
50+
assert(s.data()[3] == '\0');
51+
for (int i=0; i < 3; ++i)
52+
s[i] = 'a' + i;
53+
s.__resize_default_init(1);
54+
assert(s[0] == 'a');
55+
assert(s.data()[1] == '\0');
56+
assert(s.size() == 1);
57+
}
58+
}
59+
60+
int main() {
61+
test_basic();
62+
test_buffer_usage();
63+
}

0 commit comments

Comments
 (0)