[libcxx-commits] [libcxx] 4be7f48 - [libc++] Implement P1391 for string_view

Joe Loser via libcxx-commits libcxx-commits at lists.llvm.org
Wed Oct 6 11:19:05 PDT 2021


Author: Joe Loser
Date: 2021-10-06T14:17:10-04:00
New Revision: 4be7f48960980831a9b744c96f38ddb7dc7848ce

URL: https://github.com/llvm/llvm-project/commit/4be7f48960980831a9b744c96f38ddb7dc7848ce
DIFF: https://github.com/llvm/llvm-project/commit/4be7f48960980831a9b744c96f38ddb7dc7848ce.diff

LOG: [libc++] Implement P1391 for string_view

Implement P1391 (https://wg21.link/p1391) which allows
`std::string_view` to be constructible from any contiguous range of
characters.

Note that a different paper (http://wg21.link/P1989) handles the generic
range constructor for `std::string_view`.

Reviewed By: ldionne, Quuxplusone, Mordante, #libc

Differential Revision: https://reviews.llvm.org/D110718

Added: 
    libcxx/test/std/strings/string.view/string.view.cons/deduct.pass.cpp
    libcxx/test/std/strings/string.view/string.view.cons/from_iterator_sentinel.pass.cpp

Modified: 
    libcxx/docs/Status/Cxx20Papers.csv
    libcxx/include/string_view
    libcxx/test/support/make_string.h
    libcxx/test/support/test_iterators.h

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/Status/Cxx20Papers.csv b/libcxx/docs/Status/Cxx20Papers.csv
index ee59d657b9f2..c722b9676b4a 100644
--- a/libcxx/docs/Status/Cxx20Papers.csv
+++ b/libcxx/docs/Status/Cxx20Papers.csv
@@ -134,7 +134,7 @@
 "`P1754 <https://wg21.link/P1754>`__","LWG","Rename concepts to standard_case for C++20, while we still can","Cologne","|In Progress|",""
 "","","","","",""
 "`P0883 <https://wg21.link/P0883>`__","LWG","Fixing Atomic Initialization","Belfast","|Complete| [#note-P0883]_","13.0"
-"`P1391 <https://wg21.link/P1391>`__","LWG","Range constructor for std::string_view","Belfast","* *",""
+"`P1391 <https://wg21.link/P1391>`__","LWG","Range constructor for std::string_view","Belfast","|Complete|","14.0"
 "`P1394 <https://wg21.link/P1394>`__","LWG","Range constructor for std::span","Belfast","* *",""
 "`P1456 <https://wg21.link/P1456>`__","LWG","Move-only views","Belfast","* *",""
 "`P1622 <https://wg21.link/P1622>`__","LWG","Mandating the Standard Library: Clause 32 - Thread support library","Belfast","* *",""

diff  --git a/libcxx/include/string_view b/libcxx/include/string_view
index 33c8d6db7a1e..45bb7654930d 100644
--- a/libcxx/include/string_view
+++ b/libcxx/include/string_view
@@ -85,6 +85,8 @@ namespace std {
       constexpr basic_string_view(const charT* str);
       basic_string_view(nullptr_t) = delete; // C++2b
       constexpr basic_string_view(const charT* str, size_type len);
+      template <class It, class End>
+      constexpr basic_string_view(It begin, End end); // C++20
 
       // 7.4, basic_string_view iterator support
       constexpr const_iterator begin() const noexcept;
@@ -166,6 +168,10 @@ namespace std {
       size_type     size_;  // exposition only
     };
 
+  // basic_string_view deduction guides
+  template<class It, class End>
+    basic_string_view(It, End) -> basic_string_view<iter_value_t<It>>; // C++20
+
   // 7.11, Hash support
   template <class T> struct hash;
   template <> struct hash<string_view>;
@@ -185,6 +191,8 @@ namespace std {
 
 */
 
+#include <__concepts/convertible_to.h>
+#include <__concepts/same_as.h>
 #include <__config>
 #include <__debug>
 #include <__ranges/enable_borrowed_range.h>
@@ -270,6 +278,16 @@ public:
 #endif
     }
 
+#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_RANGES)
+    template <contiguous_iterator _It, sized_sentinel_for<_It> _End>
+      requires (same_as<iter_value_t<_It>, _CharT> && !convertible_to<_End, size_type>)
+    constexpr _LIBCPP_HIDE_FROM_ABI basic_string_view(_It __begin, _End __end)
+       : __data(_VSTD::to_address(__begin)), __size(__end - __begin)
+    {
+      _LIBCPP_ASSERT((__end - __begin) >= 0, "std::string_view::string_view(iterator, sentinel) received invalid range");
+    }
+#endif
+
     _LIBCPP_CONSTEXPR _LIBCPP_INLINE_VISIBILITY
     basic_string_view(const _CharT* __s)
         : __data(__s), __size(_VSTD::__char_traits_length_checked<_Traits>(__s)) {}
@@ -670,6 +688,13 @@ template <class _CharT, class _Traits>
 inline constexpr bool ranges::enable_borrowed_range<basic_string_view<_CharT, _Traits> > = true;
 #endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_RANGES)
 
+// [string.view.deduct]
+
+#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_RANGES)
+template <contiguous_iterator _It, sized_sentinel_for<_It> _End>
+  basic_string_view(_It, _End) -> basic_string_view<iter_value_t<_It>>;
+#endif
+
 // [string.view.comparison]
 // operator ==
 template<class _CharT, class _Traits>

diff  --git a/libcxx/test/std/strings/string.view/string.view.cons/deduct.pass.cpp b/libcxx/test/std/strings/string.view/string.view.cons/deduct.pass.cpp
new file mode 100644
index 000000000000..f838fda8e262
--- /dev/null
+++ b/libcxx/test/std/strings/string.view/string.view.cons/deduct.pass.cpp
@@ -0,0 +1,47 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+
+// <string_view>
+
+//  template <contiguous_iterator _It, sized_sentinel_for<_It> _End>
+//    basic_string_view(_It, _End) -> basic_string_view<iter_value_t<_It>>;
+
+#include <string_view>
+#include <cassert>
+
+#include "make_string.h"
+#include "test_macros.h"
+#include "test_iterators.h"
+
+template<class CharT, class Sentinel>
+constexpr void test() {
+  auto val = MAKE_STRING_VIEW(CharT, "test");
+  auto sv = std::basic_string_view(val.begin(), Sentinel(val.end()));
+  ASSERT_SAME_TYPE(decltype(sv), std::basic_string_view<CharT>);
+  assert(sv.size() == val.size());
+  assert(sv.data() == val.data());
+}
+
+constexpr void test() {
+  test<char, char*>();
+  test<wchar_t, wchar_t*>();
+  test<char8_t, char8_t*>();
+  test<char16_t, char16_t*>();
+  test<char32_t, char32_t*>();
+  test<char, const char*>();
+  test<char, sized_sentinel<const char*>>();
+}
+
+int main(int, char**) {
+  test();
+
+  return 0;
+}
+

diff  --git a/libcxx/test/std/strings/string.view/string.view.cons/from_iterator_sentinel.pass.cpp b/libcxx/test/std/strings/string.view/string.view.cons/from_iterator_sentinel.pass.cpp
new file mode 100644
index 000000000000..a65ba2763e33
--- /dev/null
+++ b/libcxx/test/std/strings/string.view/string.view.cons/from_iterator_sentinel.pass.cpp
@@ -0,0 +1,57 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// <string_view>
+
+//  template <class It, class End>
+//  constexpr basic_string_view(It begin, End end)
+
+#include <string_view>
+#include <cassert>
+#include <ranges>
+
+#include "make_string.h"
+#include "test_iterators.h"
+
+template<class CharT, class Sentinel>
+constexpr void test() {
+  auto val = MAKE_STRING_VIEW(CharT, "test");
+  auto sv = std::basic_string_view<CharT>(val.begin(), Sentinel(val.end()));
+  ASSERT_SAME_TYPE(decltype(sv), std::basic_string_view<CharT>);
+  assert(sv.size() == val.size());
+  assert(sv.data() == val.data());
+}
+
+constexpr bool test() {
+  test<char, char*>();
+  test<wchar_t, wchar_t*>();
+  test<char8_t, char8_t*>();
+  test<char16_t, char16_t*>();
+  test<char32_t, char32_t*>();
+  test<char, const char*>();
+  test<char, sized_sentinel<const char*>>();
+  return true;
+}
+
+static_assert( std::is_constructible_v<std::string_view, const char*, char*>);
+static_assert( std::is_constructible_v<std::string_view, char*, const char*>);
+static_assert(!std::is_constructible_v<std::string_view, char*, void*>);               // not a sentinel
+static_assert(!std::is_constructible_v<std::string_view, signed char*, signed char*>); // wrong char type
+static_assert(!std::is_constructible_v<std::string_view, random_access_iterator<char*>, random_access_iterator<char*>>); // not contiguous
+static_assert( std::is_constructible_v<std::string_view, contiguous_iterator<char*>, contiguous_iterator<char*>>);
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}
+

diff  --git a/libcxx/test/support/make_string.h b/libcxx/test/support/make_string.h
index 5ffcd48c10f2..1ff3dc4e5211 100644
--- a/libcxx/test/support/make_string.h
+++ b/libcxx/test/support/make_string.h
@@ -16,6 +16,7 @@
 #endif
 
 #include <string>
+#include <string_view>
 
 #if TEST_STD_VER > 17 && defined(__cpp_char8_t)
 #define CHAR8_ONLY(x) x,
@@ -56,6 +57,11 @@ struct MultiStringType {
     static_cast<const CharT*>(MultiStringType MKSTR(Str))                      \
   }
 
+#define MAKE_STRING_VIEW(CharT, Str)                                           \
+  std::basic_string_view<CharT> {                                              \
+    static_cast<const CharT*>(MultiStringType MKSTR(Str))                      \
+  }
+
 // Like MAKE_STRING but converts to a const CharT*.
 #define MAKE_CSTRING(CharT, Str)                                               \
   static_cast<const CharT*>(MultiStringType MKSTR(Str))

diff  --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h
index f0e83b46aa63..d69ceec66066 100644
--- a/libcxx/test/support/test_iterators.h
+++ b/libcxx/test/support/test_iterators.h
@@ -885,6 +885,39 @@ class sentinel_wrapper {
     I base_ = I();
 };
 
+template <std::input_or_output_iterator I>
+class sized_sentinel {
+public:
+    sized_sentinel() = default;
+    constexpr explicit sized_sentinel(I base) : base_(std::move(base)) {}
+
+    constexpr bool operator==(const I& other) const requires std::equality_comparable<I> {
+        return base_ == other;
+    }
+
+    constexpr const I& base() const& { return base_; }
+    constexpr I base() && { return std::move(base_); }
+
+    template<std::input_or_output_iterator I2>
+        requires sentinel_for_base<I, I2>
+    constexpr bool operator==(const I2& other) const {
+        return base_ == other.base();
+    }
+
+private:
+    I base_ = I();
+};
+
+template <std::input_or_output_iterator I>
+constexpr auto operator-(sized_sentinel<I> sent, std::input_or_output_iterator auto iter) {
+  return sent.base() - iter;
+}
+
+template <std::input_or_output_iterator I>
+constexpr auto operator-(std::input_or_output_iterator auto iter, sized_sentinel<I> sent) {
+  return iter - sent.base();
+}
+
 template <class It>
 class three_way_contiguous_iterator
 {


        


More information about the libcxx-commits mailing list