[libcxx] r347589 - Add basic_string::__resize_default_init (from P1072)

Eric Fiselier eric at efcs.ca
Mon Nov 26 12:15:38 PST 2018


Author: ericwf
Date: Mon Nov 26 12:15:38 2018
New Revision: 347589

URL: http://llvm.org/viewvc/llvm-project?rev=347589&view=rev
Log:
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.

Added:
    libcxx/trunk/test/libcxx/strings/basic.string/string.modifiers/resize_default_initialized.pass.cpp
Modified:
    libcxx/trunk/include/string
    libcxx/trunk/src/filesystem/filesystem_common.h

Modified: libcxx/trunk/include/string
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/string?rev=347589&r1=347588&r2=347589&view=diff
==============================================================================
--- libcxx/trunk/include/string (original)
+++ libcxx/trunk/include/string Mon Nov 26 12:15:38 2018
@@ -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 <class _ForwardIterator>
     _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS
     basic_string& __append_forward_unsafe(_ForwardIterator, _ForwardIterator);
@@ -2428,6 +2434,23 @@ basic_string<_CharT, _Traits, _Allocator
 }
 
 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>
 void
 basic_string<_CharT, _Traits, _Allocator>::push_back(value_type __c)
 {
@@ -3082,6 +3105,17 @@ basic_string<_CharT, _Traits, _Allocator
         __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>
 inline _LIBCPP_INLINE_VISIBILITY
 typename basic_string<_CharT, _Traits, _Allocator>::size_type

Modified: libcxx/trunk/src/filesystem/filesystem_common.h
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/src/filesystem/filesystem_common.h?rev=347589&r1=347588&r2=347589&view=diff
==============================================================================
--- libcxx/trunk/src/filesystem/filesystem_common.h (original)
+++ libcxx/trunk/src/filesystem/filesystem_common.h Mon Nov 26 12:15:38 2018
@@ -67,24 +67,31 @@ static string format_string_imp(const ch
   va_copy(args_cp, args);
   GuardVAList args_copy_guard(args_cp);
 
+  std::string result;
+
   array<char, 256> 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<size_t>(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<size_t>(ret) + 1;
-  auto buff_ptr = unique_ptr<char[]>(new char[size]);
-  ret = ::vsnprintf(buff_ptr.get(), size, msg, args);
-  return string(buff_ptr.get());
+    return result;
+  if (static_cast<size_t>(ret) < size_with_null) {
+    result.assign(local_buff.data(), static_cast<size_t>(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<size_t>(ret) + 1;
+  result.__resize_default_init(size_with_null - 1);
+  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(); }

Added: libcxx/trunk/test/libcxx/strings/basic.string/string.modifiers/resize_default_initialized.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/strings/basic.string/string.modifiers/resize_default_initialized.pass.cpp?rev=347589&view=auto
==============================================================================
--- libcxx/trunk/test/libcxx/strings/basic.string/string.modifiers/resize_default_initialized.pass.cpp (added)
+++ libcxx/trunk/test/libcxx/strings/basic.string/string.modifiers/resize_default_initialized.pass.cpp Mon Nov 26 12:15:38 2018
@@ -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();
+}




More information about the libcxx-commits mailing list