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
This commit is contained in:
Eric Fiselier 2018-11-26 20:15:38 +00:00
parent e8e8c5cf4d
commit 01a87ef88b
3 changed files with 115 additions and 11 deletions

View File

@ -956,6 +956,8 @@ public:
void resize(size_type __n, value_type __c); void resize(size_type __n, value_type __c);
_LIBCPP_INLINE_VISIBILITY void resize(size_type __n) {resize(__n, value_type());} _LIBCPP_INLINE_VISIBILITY void resize(size_type __n) {resize(__n, value_type());}
_LIBCPP_INLINE_VISIBILITY void __resize_default_init(size_type __n);
void reserve(size_type __res_arg = 0); void reserve(size_type __res_arg = 0);
_LIBCPP_INLINE_VISIBILITY _LIBCPP_INLINE_VISIBILITY
void shrink_to_fit() _NOEXCEPT {reserve();} void shrink_to_fit() _NOEXCEPT {reserve();}
@ -1010,6 +1012,10 @@ public:
basic_string& append(const value_type* __s, size_type __n); basic_string& append(const value_type* __s, size_type __n);
basic_string& append(const value_type* __s); basic_string& append(const value_type* __s);
basic_string& append(size_type __n, value_type __c); basic_string& append(size_type __n, value_type __c);
_LIBCPP_INLINE_VISIBILITY
void __append_default_init(size_type __n);
template <class _ForwardIterator> template <class _ForwardIterator>
_LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
basic_string& __append_forward_unsafe(_ForwardIterator, _ForwardIterator); basic_string& __append_forward_unsafe(_ForwardIterator, _ForwardIterator);
@ -2427,6 +2433,23 @@ basic_string<_CharT, _Traits, _Allocator>::append(size_type __n, value_type __c)
return *this; return *this;
} }
template <class _CharT, class _Traits, class _Allocator>
inline void
basic_string<_CharT, _Traits, _Allocator>::__append_default_init(size_type __n)
{
if (__n)
{
size_type __cap = capacity();
size_type __sz = size();
if (__cap - __sz < __n)
__grow_by(__cap, __sz + __n - __cap, __sz, __sz, 0);
pointer __p = __get_pointer();
__sz += __n;
__set_size(__sz);
traits_type::assign(__p[__sz], value_type());
}
}
template <class _CharT, class _Traits, class _Allocator> template <class _CharT, class _Traits, class _Allocator>
void void
basic_string<_CharT, _Traits, _Allocator>::push_back(value_type __c) 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)
__erase_to_end(__n); __erase_to_end(__n);
} }
template <class _CharT, class _Traits, class _Allocator>
inline void
basic_string<_CharT, _Traits, _Allocator>::__resize_default_init(size_type __n)
{
size_type __sz = size();
if (__n > __sz) {
__append_default_init(__n - __sz);
} else
__erase_to_end(__n);
}
template <class _CharT, class _Traits, class _Allocator> template <class _CharT, class _Traits, class _Allocator>
inline _LIBCPP_INLINE_VISIBILITY inline _LIBCPP_INLINE_VISIBILITY
typename basic_string<_CharT, _Traits, _Allocator>::size_type typename basic_string<_CharT, _Traits, _Allocator>::size_type

View File

@ -67,24 +67,31 @@ static string format_string_imp(const char* msg, ...) {
va_copy(args_cp, args); va_copy(args_cp, args);
GuardVAList args_copy_guard(args_cp); GuardVAList args_copy_guard(args_cp);
std::string result;
array<char, 256> local_buff; array<char, 256> local_buff;
size_t size = local_buff.size(); size_t size_with_null = local_buff.size();
auto ret = ::vsnprintf(local_buff.data(), size, msg, args_cp); auto ret = ::vsnprintf(local_buff.data(), size_with_null, msg, args_cp);
args_copy_guard.clear(); args_copy_guard.clear();
// handle empty expansion // handle empty expansion
if (ret == 0) if (ret == 0)
return string{}; return result;
if (static_cast<size_t>(ret) < size) if (static_cast<size_t>(ret) < size_with_null) {
return string(local_buff.data()); result.assign(local_buff.data(), static_cast<size_t>(ret));
return result;
}
// we did not provide a long enough buffer on our first attempt. // we did not provide a long enough buffer on our first attempt. The
// add 1 to size to account for null-byte in size cast to prevent overflow // return value is the number of bytes (excluding the null byte) that are
size = static_cast<size_t>(ret) + 1; // needed for formatting.
auto buff_ptr = unique_ptr<char[]>(new char[size]); size_with_null = static_cast<size_t>(ret) + 1;
ret = ::vsnprintf(buff_ptr.get(), size, msg, args); result.__resize_default_init(size_with_null - 1);
return string(buff_ptr.get()); ret = ::vsnprintf(&result[0], size_with_null, msg, args);
_LIBCPP_ASSERT(static_cast<size_t>(ret) == (size_with_null - 1), "TODO");
return result;
} }
const char* unwrap(string const& s) { return s.c_str(); } const char* unwrap(string const& s) { return s.c_str(); }

View File

@ -0,0 +1,63 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// <string>
// __resize_default_init(size_type)
#include <string>
#include <cassert>
#include "test_macros.h"
void write_c_str(char *buf, int size) {
for (int i=0; i < size; ++i) {
buf[i] = 'a';
}
buf[size] = '\0';
}
void test_buffer_usage()
{
{
unsigned buff_size = 125;
unsigned used_size = buff_size - 16;
std::string s;
s.__resize_default_init(buff_size);
write_c_str(&s[0], used_size);
assert(s.size() == buff_size);
assert(strlen(s.data()) == used_size);
s.__resize_default_init(used_size);
assert(s.size() == used_size);
assert(s.data()[used_size] == '\0');
for (unsigned i=0; i < used_size; ++i) {
assert(s[i] == 'a');
}
}
}
void test_basic() {
{
std::string s;
s.__resize_default_init(3);
assert(s.size() == 3);
assert(s.data()[3] == '\0');
for (int i=0; i < 3; ++i)
s[i] = 'a' + i;
s.__resize_default_init(1);
assert(s[0] == 'a');
assert(s.data()[1] == '\0');
assert(s.size() == 1);
}
}
int main() {
test_basic();
test_buffer_usage();
}