From 01a87ef88b77034ab6a9ea7bc9da24fb380e91e8 Mon Sep 17 00:00:00 2001 From: Eric Fiselier Date: Mon, 26 Nov 2018 20:15:38 +0000 Subject: [PATCH] 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 --- libcxx/include/string | 34 ++++++++++++ libcxx/src/filesystem/filesystem_common.h | 31 ++++++----- .../resize_default_initialized.pass.cpp | 63 ++++++++++++++++++++++ 3 files changed, 116 insertions(+), 12 deletions(-) create mode 100644 libcxx/test/libcxx/strings/basic.string/string.modifiers/resize_default_initialized.pass.cpp diff --git a/libcxx/include/string b/libcxx/include/string index 0c9f1cf..383b5c0 100644 --- a/libcxx/include/string +++ b/libcxx/include/string @@ -956,6 +956,8 @@ public: 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_default_init(size_type __n); + void reserve(size_type __res_arg = 0); _LIBCPP_INLINE_VISIBILITY 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); basic_string& append(size_type __n, value_type __c); + + _LIBCPP_INLINE_VISIBILITY + void __append_default_init(size_type __n); + template _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS basic_string& __append_forward_unsafe(_ForwardIterator, _ForwardIterator); @@ -2428,6 +2434,23 @@ basic_string<_CharT, _Traits, _Allocator>::append(size_type __n, value_type __c) } template +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 void basic_string<_CharT, _Traits, _Allocator>::push_back(value_type __c) { @@ -3083,6 +3106,17 @@ basic_string<_CharT, _Traits, _Allocator>::resize(size_type __n, value_type __c) } template +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 inline _LIBCPP_INLINE_VISIBILITY typename basic_string<_CharT, _Traits, _Allocator>::size_type basic_string<_CharT, _Traits, _Allocator>::max_size() const _NOEXCEPT diff --git a/libcxx/src/filesystem/filesystem_common.h b/libcxx/src/filesystem/filesystem_common.h index ed92877..40419ee 100644 --- a/libcxx/src/filesystem/filesystem_common.h +++ b/libcxx/src/filesystem/filesystem_common.h @@ -67,24 +67,31 @@ static string format_string_imp(const char* msg, ...) { va_copy(args_cp, args); GuardVAList args_copy_guard(args_cp); + std::string result; + array local_buff; - size_t size = local_buff.size(); - auto ret = ::vsnprintf(local_buff.data(), size, msg, args_cp); + size_t size_with_null = local_buff.size(); + auto ret = ::vsnprintf(local_buff.data(), size_with_null, msg, args_cp); args_copy_guard.clear(); // handle empty expansion if (ret == 0) - return string{}; - if (static_cast(ret) < size) - return string(local_buff.data()); - - // we did not provide a long enough buffer on our first attempt. - // add 1 to size to account for null-byte in size cast to prevent overflow - size = static_cast(ret) + 1; - auto buff_ptr = unique_ptr(new char[size]); - ret = ::vsnprintf(buff_ptr.get(), size, msg, args); - return string(buff_ptr.get()); + return result; + if (static_cast(ret) < size_with_null) { + result.assign(local_buff.data(), static_cast(ret)); + return result; + } + + // we did not provide a long enough buffer on our first attempt. The + // return value is the number of bytes (excluding the null byte) that are + // needed for formatting. + size_with_null = static_cast(ret) + 1; + result.__resize_default_init(size_with_null - 1); + ret = ::vsnprintf(&result[0], size_with_null, msg, args); + _LIBCPP_ASSERT(static_cast(ret) == (size_with_null - 1), "TODO"); + + return result; } const char* unwrap(string const& s) { return s.c_str(); } diff --git a/libcxx/test/libcxx/strings/basic.string/string.modifiers/resize_default_initialized.pass.cpp b/libcxx/test/libcxx/strings/basic.string/string.modifiers/resize_default_initialized.pass.cpp new file mode 100644 index 0000000..a3fa585 --- /dev/null +++ b/libcxx/test/libcxx/strings/basic.string/string.modifiers/resize_default_initialized.pass.cpp @@ -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. +// +//===----------------------------------------------------------------------===// + +// + +// __resize_default_init(size_type) + +#include +#include + +#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(); +} -- 2.7.4