[libcxx-commits] [libcxx] 29378ab - [libc++] Implement P2438R2 (std::string::substr() &&)
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Wed Nov 2 12:28:53 PDT 2022
Author: Nikolas Klauser
Date: 2022-11-02T20:28:47+01:00
New Revision: 29378ab24b98137b4959034a0882c3bbd97c46e4
URL: https://github.com/llvm/llvm-project/commit/29378ab24b98137b4959034a0882c3bbd97c46e4
DIFF: https://github.com/llvm/llvm-project/commit/29378ab24b98137b4959034a0882c3bbd97c46e4.diff
LOG: [libc++] Implement P2438R2 (std::string::substr() &&)
This doesn't affect our ABI because `std::string::substr()` isn't in the dylib and the mangling of `substr() const` and `substr() const&` are different.
Reviewed By: ldionne, Mordante, var-const, avogelsgesang, #libc
Spies: arphaman, huixie90, libcxx-commits
Differential Revision: https://reviews.llvm.org/D131668
Added:
libcxx/test/libcxx/strings/basic.string/string.cons/debug.iterator.substr.pass.cpp
libcxx/test/std/strings/basic.string/string.cons/substr_rvalue.pass.cpp
libcxx/test/std/strings/basic.string/string.ops/string_substr/substr_rvalue.pass.cpp
Modified:
libcxx/docs/ReleaseNotes.rst
libcxx/docs/Status/Cxx2bPapers.csv
libcxx/include/string
libcxx/test/libcxx/strings/basic.string/string.iterators/debug.iterator.index.pass.cpp
libcxx/test/std/strings/basic.string/string.ops/string_substr/substr.pass.cpp
libcxx/test/support/count_new.h
libcxx/test/support/make_string.h
Removed:
################################################################################
diff --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst
index d10fdde8d719f..abcebeb01ebee 100644
--- a/libcxx/docs/ReleaseNotes.rst
+++ b/libcxx/docs/ReleaseNotes.rst
@@ -46,6 +46,7 @@ Implemented Papers
``from_chars`` for Integral Types in ``<charconv>`` Header
- P0220R1 - Adopt Library Fundamentals V1 TS Components for C++17
- P0482R6 - char8_t: A type for UTF-8 characters and strings
+- P2438R2 - ``std::string::substr() &&``
Improvements and New Features
-----------------------------
diff --git a/libcxx/docs/Status/Cxx2bPapers.csv b/libcxx/docs/Status/Cxx2bPapers.csv
index 7017c31a92c41..f40cca9c7ac60 100644
--- a/libcxx/docs/Status/Cxx2bPapers.csv
+++ b/libcxx/docs/Status/Cxx2bPapers.csv
@@ -71,7 +71,7 @@
"`P2408R5 <https://wg21.link/P2408R5>`__","LWG","Ranges iterators as inputs to non-Ranges algorithms","July 2022","",""
"`P2417R2 <https://wg21.link/P2417R2>`__","LWG","A more ``constexpr`` ``bitset``","July 2022","|Complete|","16.0"
"`P2419R2 <https://wg21.link/P2419R2>`__","LWG","Clarify handling of encodings in localized formatting of chrono types","July 2022","",""
-"`P2438R2 <https://wg21.link/P2438R2>`__","LWG","``std::string::substr() &&``","July 2022","",""
+"`P2438R2 <https://wg21.link/P2438R2>`__","LWG","``std::string::substr() &&``","July 2022","|Complete|","16.0"
"`P2445R1 <https://wg21.link/P2445R1>`__","LWG","``forward_like``","July 2022","|Complete|","16.0"
"`P2446R2 <https://wg21.link/P2446R2>`__","LWG","``views::as_rvalue``","July 2022","",""
"`P2460R2 <https://wg21.link/P2460R2>`__","LWG","Relax requirements on ``wchar_t`` to match existing practices","July 2022","",""
diff --git a/libcxx/include/string b/libcxx/include/string
index 8eb1d30970421..726bba3156f6e 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -109,6 +109,10 @@ public:
const allocator_type& a = allocator_type()); // constexpr since C++20
basic_string(const basic_string& str, size_type pos, size_type n,
const Allocator& a = Allocator()); // constexpr since C++20
+ constexpr basic_string(
+ basic_string&& str, size_type pos, const Allocator& a = Allocator()); // since C++23
+ constexpr basic_string(
+ basic_string&& str, size_type pos, size_type n, const Allocator& a = Allocator()); // since C++23
template<class T>
basic_string(const T& t, size_type pos, size_type n, const Allocator& a = Allocator()); // C++17, constexpr since C++20
template <class T>
@@ -261,8 +265,9 @@ public:
basic_string& replace(const_iterator i1, const_iterator i2, initializer_list<value_type>); // constexpr since C++20
size_type copy(value_type* s, size_type n, size_type pos = 0) const; // constexpr since C++20
- basic_string substr(size_type pos = 0, size_type n = npos) const; // constexpr since C++20
-
+ basic_string substr(size_type pos = 0, size_type n = npos) const; // constexpr in C++20, removed in C++23
+ basic_string substr(size_type pos = 0, size_type n = npos) const&; // since C++23
+ constexpr basic_string substr(size_type pos = 0, size_type n = npos) &&; // since C++23
void swap(basic_string& str)
noexcept(allocator_traits<allocator_type>::propagate_on_container_swap::value ||
allocator_traits<allocator_type>::is_always_equal::value); // C++17, constexpr since C++20
@@ -897,6 +902,36 @@ public:
std::__debug_db_insert_c(this);
}
+#if _LIBCPP_STD_VER > 20
+ _LIBCPP_HIDE_FROM_ABI constexpr
+ basic_string(basic_string&& __str, size_type __pos, const _Allocator& __alloc = _Allocator())
+ : basic_string(std::move(__str), __pos, npos, __alloc) {}
+
+ _LIBCPP_HIDE_FROM_ABI constexpr
+ basic_string(basic_string&& __str, size_type __pos, size_type __n, const _Allocator& __alloc = _Allocator())
+ : __r_(__default_init_tag(), __alloc) {
+ if (__pos > __str.size())
+ __throw_out_of_range();
+
+ auto __len = std::min<size_type>(__n, __str.size() - __pos);
+ if (__alloc_traits::is_always_equal::value || __alloc == __str.__alloc()) {
+ __r_.first() = __str.__r_.first();
+ __str.__default_init();
+
+ _Traits::move(data(), data() + __pos, __len);
+ __set_size(__len);
+ _Traits::assign(data()[__len], value_type());
+ } else {
+ // Perform a copy because the allocators are not compatible.
+ __init(__str.data() + __pos, __len);
+ }
+
+ std::__debug_db_insert_c(this);
+ if (__is_long())
+ std::__debug_db_swap(this, &__str);
+ }
+#endif
+
template <class = __enable_if_t<__is_allocator<_Allocator>::value, nullptr_t> >
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string(size_type __n, _CharT __c, const _Allocator& __a);
@@ -1324,8 +1359,24 @@ public:
#endif // _LIBCPP_CXX03_LANG
_LIBCPP_CONSTEXPR_SINCE_CXX20 size_type copy(value_type* __s, size_type __n, size_type __pos = 0) const;
+
+ // TODO: Maybe don't pass in the allocator. See https://llvm.org/PR57190
+#if _LIBCPP_STD_VER <= 20
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
- basic_string substr(size_type __pos = 0, size_type __n = npos) const;
+ basic_string substr(size_type __pos = 0, size_type __n = npos) const {
+ return basic_string(*this, __pos, __n, __alloc());
+ }
+#else
+ _LIBCPP_HIDE_FROM_ABI constexpr
+ basic_string substr(size_type __pos = 0, size_type __n = npos) const& {
+ return basic_string(*this, __pos, __n, __alloc());
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr
+ basic_string substr(size_type __pos = 0, size_type __n = npos) && {
+ return basic_string(std::move(*this), __pos, __n, __alloc());
+ }
+#endif
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
void swap(basic_string& __str)
@@ -3472,14 +3523,6 @@ basic_string<_CharT, _Traits, _Allocator>::copy(value_type* __s, size_type __n,
return __rlen;
}
-template <class _CharT, class _Traits, class _Allocator>
-inline _LIBCPP_CONSTEXPR_SINCE_CXX20
-basic_string<_CharT, _Traits, _Allocator>
-basic_string<_CharT, _Traits, _Allocator>::substr(size_type __pos, size_type __n) const
-{
- return basic_string(*this, __pos, __n, __alloc());
-}
-
template <class _CharT, class _Traits, class _Allocator>
inline _LIBCPP_CONSTEXPR_SINCE_CXX20
void
diff --git a/libcxx/test/libcxx/strings/basic.string/string.cons/debug.iterator.substr.pass.cpp b/libcxx/test/libcxx/strings/basic.string/string.cons/debug.iterator.substr.pass.cpp
new file mode 100644
index 0000000000000..8eeb26233acc7
--- /dev/null
+++ b/libcxx/test/libcxx/strings/basic.string/string.cons/debug.iterator.substr.pass.cpp
@@ -0,0 +1,49 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <string>
+
+// Check that basic_string(basic_string&&, size_type, Allocator) and
+// basic_string(basic_string&&, size_type, size_type, Allocator) inserts the container into the debug database
+
+// REQUIRES: has-unix-headers
+// UNSUPPORTED: !libcpp-has-debug-mode, c++03
+
+#include <cassert>
+#include <string>
+
+#include "check_assertion.h"
+
+int main(int, char**) {
+ using namespace std::string_literals;
+
+ {
+ std::string s = {"Banane"s, 1};
+ auto i = s.begin();
+ assert(i[0] == 'a');
+ TEST_LIBCPP_ASSERT_FAILURE(i[5], "Attempted to subscript an iterator outside its valid range");
+ }
+ {
+ std::string s = {"Banane"s, 0, 5};
+ auto i = s.begin();
+ assert(i[0] == 'B');
+ TEST_LIBCPP_ASSERT_FAILURE(i[5], "Attempted to subscript an iterator outside its valid range");
+ }
+ {
+ std::string s = {"long long string so no SSO"s, 21};
+ auto i = s.begin();
+ assert(i[0] == 'o');
+ TEST_LIBCPP_ASSERT_FAILURE(i[5], "Attempted to subscript an iterator outside its valid range");
+ }
+ {
+ std::string s = {"long long string so no SSO"s, 0, 5};
+ auto i = s.begin();
+ assert(i[0] == 'l');
+ TEST_LIBCPP_ASSERT_FAILURE(i[5], "Attempted to subscript an iterator outside its valid range");
+ }
+}
diff --git a/libcxx/test/libcxx/strings/basic.string/string.iterators/debug.iterator.index.pass.cpp b/libcxx/test/libcxx/strings/basic.string/string.iterators/debug.iterator.index.pass.cpp
index f1b4e5666569b..13a2301937309 100644
--- a/libcxx/test/libcxx/strings/basic.string/string.iterators/debug.iterator.index.pass.cpp
+++ b/libcxx/test/libcxx/strings/basic.string/string.iterators/debug.iterator.index.pass.cpp
@@ -20,6 +20,7 @@
#include "min_allocator.h"
int main(int, char**) {
+ using T = decltype(uint8_t() - uint8_t());
{
typedef std::string C;
C c(1, '\0');
diff --git a/libcxx/test/std/strings/basic.string/string.cons/substr_rvalue.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/substr_rvalue.pass.cpp
new file mode 100644
index 0000000000000..6a431be5cf851
--- /dev/null
+++ b/libcxx/test/std/strings/basic.string/string.cons/substr_rvalue.pass.cpp
@@ -0,0 +1,233 @@
+//===----------------------------------------------------------------------===//
+//
+// 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, c++20
+
+// <string>
+
+// constexpr basic_string(basic_string&& str, size_type pos, const Allocator& a = Allocator());
+// constexpr basic_string(basic_string&& str, size_type pos, size_type n, const Allocator& a = Allocator());
+
+#include <cassert>
+#include <string>
+
+#include "constexpr_char_traits.h"
+#include "count_new.h"
+#include "make_string.h"
+#include "min_allocator.h"
+#include "test_allocator.h"
+#include "test_macros.h"
+
+#define STR(string) MAKE_CSTRING(typename S::value_type, string)
+
+constexpr struct should_throw_exception_t {
+} should_throw_exception;
+
+template <class S>
+constexpr void test_string_pos(S orig, typename S::size_type pos, S expected) {
+#ifdef _LIBCPP_VERSION
+ ConstexprDisableAllocationGuard g;
+#endif
+ S substr(std::move(orig), pos);
+ LIBCPP_ASSERT(orig.__invariants());
+ LIBCPP_ASSERT(orig.empty());
+ LIBCPP_ASSERT(substr.__invariants());
+ assert(substr == expected);
+}
+
+template <class S>
+constexpr void test_string_pos(S orig, typename S::size_type pos, should_throw_exception_t) {
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ if (!std::is_constant_evaluated()) {
+ try {
+ [[maybe_unused]] S substr = S(std::move(orig), pos);
+ assert(false);
+ } catch (const std::out_of_range&) {
+ }
+ }
+#else
+ (void)orig;
+ (void)pos;
+#endif
+}
+
+template <class S>
+constexpr void
+test_string_pos_alloc(S orig, typename S::size_type pos, const typename S::allocator_type& alloc, S expected) {
+ S substr(std::move(orig), pos, alloc);
+ LIBCPP_ASSERT(orig.__invariants());
+ LIBCPP_ASSERT(substr.__invariants());
+ assert(substr == expected);
+ assert(substr.get_allocator() == alloc);
+}
+
+template <class S>
+constexpr void test_string_pos_alloc(
+ S orig, typename S::size_type pos, const typename S::allocator_type& alloc, should_throw_exception_t) {
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ if (!std::is_constant_evaluated()) {
+ try {
+ [[maybe_unused]] S substr = S(std::move(orig), pos, alloc);
+ assert(false);
+ } catch (const std::out_of_range&) {
+ }
+ }
+#else
+ (void)orig;
+ (void)pos;
+ (void)alloc;
+#endif
+}
+
+template <class S>
+constexpr void test_string_pos_n(S orig, typename S::size_type pos, typename S::size_type n, S expected) {
+#ifdef _LIBCPP_VERSION
+ ConstexprDisableAllocationGuard g;
+#endif
+ S substr(std::move(orig), pos, n);
+ LIBCPP_ASSERT(orig.__invariants());
+ LIBCPP_ASSERT(orig.empty());
+ LIBCPP_ASSERT(substr.__invariants());
+ assert(substr == expected);
+}
+
+template <class S>
+constexpr void test_string_pos_n(S orig, typename S::size_type pos, typename S::size_type n, should_throw_exception_t) {
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ if (!std::is_constant_evaluated()) {
+ try {
+ [[maybe_unused]] S substr = S(std::move(orig), pos, n);
+ assert(false);
+ } catch (const std::out_of_range&) {
+ }
+ }
+#else
+ (void)orig;
+ (void)pos;
+ (void)n;
+#endif
+}
+
+template <class S>
+constexpr void test_string_pos_n_alloc(
+ S orig, typename S::size_type pos, typename S::size_type n, const typename S::allocator_type& alloc, S expected) {
+ S substr(std::move(orig), pos, n, alloc);
+ LIBCPP_ASSERT(orig.__invariants());
+ LIBCPP_ASSERT(substr.__invariants());
+ assert(substr == expected);
+ assert(substr.get_allocator() == alloc);
+}
+
+template <class S>
+constexpr void test_string_pos_n_alloc(
+ S orig,
+ typename S::size_type pos,
+ typename S::size_type n,
+ const typename S::allocator_type& alloc,
+ should_throw_exception_t) {
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ if (!std::is_constant_evaluated()) {
+ try {
+ [[maybe_unused]] S substr = S(std::move(orig), pos, n, alloc);
+ assert(false);
+ } catch (const std::out_of_range&) {
+ }
+ }
+#else
+ (void)orig;
+ (void)pos;
+ (void)n;
+ (void)alloc;
+#endif
+}
+
+template <class S>
+constexpr void test_string(const typename S::allocator_type& alloc) {
+ test_string_pos<S>(STR(""), 0, STR(""));
+ test_string_pos<S>(STR(""), 1, should_throw_exception);
+ test_string_pos<S>(STR("Banane"), 1, STR("anane"));
+ test_string_pos<S>(STR("Banane"), 6, STR(""));
+ test_string_pos<S>(STR("Banane"), 7, should_throw_exception);
+ test_string_pos<S>(STR("long long string so no SSO"), 0, STR("long long string so no SSO"));
+ test_string_pos<S>(STR("long long string so no SSO"), 10, STR("string so no SSO"));
+ test_string_pos<S>(STR("long long string so no SSO"), 26, STR(""));
+ test_string_pos<S>(STR("long long string so no SSO"), 27, should_throw_exception);
+
+ test_string_pos_alloc<S>(STR(""), 0, alloc, STR(""));
+ test_string_pos_alloc<S>(STR(""), 1, alloc, should_throw_exception);
+ test_string_pos_alloc<S>(STR("Banane"), 1, alloc, STR("anane"));
+ test_string_pos_alloc<S>(STR("Banane"), 6, alloc, STR(""));
+ test_string_pos_alloc<S>(STR("Banane"), 7, alloc, should_throw_exception);
+ test_string_pos_alloc<S>(STR("long long string so no SSO"), 0, alloc, STR("long long string so no SSO"));
+ test_string_pos_alloc<S>(STR("long long string so no SSO"), 10, alloc, STR("string so no SSO"));
+ test_string_pos_alloc<S>(STR("long long string so no SSO"), 26, alloc, STR(""));
+ test_string_pos_alloc<S>(STR("long long string so no SSO"), 27, alloc, should_throw_exception);
+
+ test_string_pos_n<S>(STR(""), 0, 0, STR(""));
+ test_string_pos_n<S>(STR(""), 0, 1, STR(""));
+ test_string_pos_n<S>(STR(""), 1, 0, should_throw_exception);
+ test_string_pos_n<S>(STR(""), 1, 1, should_throw_exception);
+ test_string_pos_n<S>(STR("Banane"), 1, 10, STR("anane"));
+ test_string_pos_n<S>(STR("Banane"), 6, 0, STR(""));
+ test_string_pos_n<S>(STR("Banane"), 6, 5, STR(""));
+ test_string_pos_n<S>(STR("Banane"), 7, 10, should_throw_exception);
+ test_string_pos_n<S>(STR("long long string so no SSO"), 0, 10, STR("long long "));
+ test_string_pos_n<S>(STR("long long string so no SSO"), 10, 8, STR("string s"));
+ test_string_pos_n<S>(STR("long long string so no SSO"), 20, 10, STR("no SSO"));
+ test_string_pos_n<S>(STR("long long string so no SSO"), 26, 10, STR(""));
+ test_string_pos_n<S>(STR("long long string so no SSO"), 27, 10, should_throw_exception);
+
+ test_string_pos_n_alloc<S>(STR(""), 0, 0, alloc, STR(""));
+ test_string_pos_n_alloc<S>(STR(""), 0, 1, alloc, STR(""));
+ test_string_pos_n_alloc<S>(STR(""), 1, 0, alloc, should_throw_exception);
+ test_string_pos_n_alloc<S>(STR(""), 1, 1, alloc, should_throw_exception);
+ test_string_pos_n_alloc<S>(STR("Banane"), 1, 10, alloc, STR("anane"));
+ test_string_pos_n_alloc<S>(STR("Banane"), 6, 0, alloc, STR(""));
+ test_string_pos_n_alloc<S>(STR("Banane"), 6, 5, alloc, STR(""));
+ test_string_pos_n_alloc<S>(STR("Banane"), 7, 10, alloc, should_throw_exception);
+ test_string_pos_n_alloc<S>(STR("long long string so no SSO"), 0, 10, alloc, STR("long long "));
+ test_string_pos_n_alloc<S>(STR("long long string so no SSO"), 10, 8, alloc, STR("string s"));
+ test_string_pos_n_alloc<S>(STR("long long string so no SSO"), 20, 10, alloc, STR("no SSO"));
+ test_string_pos_n_alloc<S>(STR("long long string so no SSO"), 26, 10, alloc, STR(""));
+ test_string_pos_n_alloc<S>(STR("long long string so no SSO"), 27, 10, alloc, should_throw_exception);
+}
+
+template <class CharT, class CharTraits>
+constexpr void test_allocators() {
+ test_string<std::basic_string<CharT, CharTraits, std::allocator<CharT>>>(std::allocator<CharT>{});
+ test_string<std::basic_string<CharT, CharTraits, min_allocator<CharT>>>(min_allocator<CharT>{});
+ test_string<std::basic_string<CharT, CharTraits, test_allocator<CharT>>>(test_allocator<CharT>{42});
+}
+
+template <class CharT>
+constexpr bool test_char_traits() {
+ test_allocators<CharT, std::char_traits<CharT>>();
+ test_allocators<CharT, constexpr_char_traits<CharT>>();
+
+ return true;
+}
+
+int main(int, char**) {
+ // TODO: put these into a single function when we increase the constexpr step limit
+ test_char_traits<char>();
+ static_assert(test_char_traits<char>());
+ test_char_traits<char16_t>();
+ static_assert(test_char_traits<char16_t>());
+ test_char_traits<char32_t>();
+ static_assert(test_char_traits<char32_t>());
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+ test_char_traits<wchar_t>();
+ static_assert(test_char_traits<wchar_t>());
+#endif
+#ifndef TEST_HAS_NO_CHAR8_T
+ test_char_traits<char8_t>();
+ static_assert(test_char_traits<char8_t>());
+#endif
+
+ return 0;
+}
diff --git a/libcxx/test/std/strings/basic.string/string.ops/string_substr/substr.pass.cpp b/libcxx/test/std/strings/basic.string/string.ops/string_substr/substr.pass.cpp
index 4ae469d597a0f..7f6404abd8261 100644
--- a/libcxx/test/std/strings/basic.string/string.ops/string_substr/substr.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.ops/string_substr/substr.pass.cpp
@@ -8,7 +8,8 @@
// <string>
-// basic_string substr(size_type pos = 0, size_type n = npos) const; // constexpr since C++20
+// basic_string substr(size_type pos = 0, size_type n = npos) const; // constexpr since C++20, removed in C++23
+// basic_string substr(size_type pos = 0, size_type n = npos) const&; // since in C++23
#include <string>
#include <stdexcept>
@@ -47,130 +48,72 @@ test(const S& s, typename S::size_type pos, typename S::size_type n)
#endif
}
+template <class S>
+TEST_CONSTEXPR_CXX20 void test_string() {
+ test(S(""), 0, 0);
+ test(S(""), 1, 0);
+ test(S("pniot"), 0, 0);
+ test(S("htaob"), 0, 1);
+ test(S("fodgq"), 0, 2);
+ test(S("hpqia"), 0, 4);
+ test(S("qanej"), 0, 5);
+ test(S("dfkap"), 1, 0);
+ test(S("clbao"), 1, 1);
+ test(S("ihqrf"), 1, 2);
+ test(S("mekdn"), 1, 3);
+ test(S("ngtjf"), 1, 4);
+ test(S("srdfq"), 2, 0);
+ test(S("qkdrs"), 2, 1);
+ test(S("ikcrq"), 2, 2);
+ test(S("cdaih"), 2, 3);
+ test(S("dmajb"), 4, 0);
+ test(S("karth"), 4, 1);
+ test(S("lhcdo"), 5, 0);
+ test(S("acbsj"), 6, 0);
+ test(S("pbsjikaole"), 0, 0);
+ test(S("pcbahntsje"), 0, 1);
+ test(S("mprdjbeiak"), 0, 5);
+ test(S("fhepcrntko"), 0, 9);
+ test(S("eqmpaidtls"), 0, 10);
+ test(S("joidhalcmq"), 1, 0);
+ test(S("omigsphflj"), 1, 1);
+ test(S("kocgbphfji"), 1, 4);
+ test(S("onmjekafbi"), 1, 8);
+ test(S("fbslrjiqkm"), 1, 9);
+ test(S("oqmrjahnkg"), 5, 0);
+ test(S("jeidpcmalh"), 5, 1);
+ test(S("schfalibje"), 5, 2);
+ test(S("crliponbqe"), 5, 4);
+ test(S("igdscopqtm"), 5, 5);
+ test(S("qngpdkimlc"), 9, 0);
+ test(S("thdjgafrlb"), 9, 1);
+ test(S("hcjitbfapl"), 10, 0);
+ test(S("mgojkldsqh"), 11, 0);
+ test(S("gfshlcmdjreqipbontak"), 0, 0);
+ test(S("nadkhpfemgclosibtjrq"), 0, 1);
+ test(S("nkodajteqplrbifhmcgs"), 0, 10);
+ test(S("ofdrqmkeblthacpgijsn"), 0, 19);
+ test(S("gbmetiprqdoasckjfhln"), 0, 20);
+ test(S("bdfjqgatlksriohemnpc"), 1, 0);
+ test(S("crnklpmegdqfiashtojb"), 1, 1);
+ test(S("ejqcnahdrkfsmptilgbo"), 1, 9);
+ test(S("jsbtafedocnirgpmkhql"), 1, 18);
+ test(S("prqgnlbaejsmkhdctoif"), 1, 19);
+ test(S("qnmodrtkebhpasifgcjl"), 10, 0);
+ test(S("pejafmnokrqhtisbcdgl"), 10, 1);
+ test(S("cpebqsfmnjdolhkratgi"), 10, 5);
+ test(S("odnqkgijrhabfmcestlp"), 10, 9);
+ test(S("lmofqdhpkibagnrcjste"), 10, 10);
+ test(S("lgjqketopbfahrmnsicd"), 19, 0);
+ test(S("ktsrmnqagdecfhijpobl"), 19, 1);
+ test(S("lsaijeqhtrbgcdmpfkno"), 20, 0);
+ test(S("dplqartnfgejichmoskb"), 21, 0);
+}
+
TEST_CONSTEXPR_CXX20 bool test() {
- {
- typedef std::string S;
- test(S(""), 0, 0);
- test(S(""), 1, 0);
- test(S("pniot"), 0, 0);
- test(S("htaob"), 0, 1);
- test(S("fodgq"), 0, 2);
- test(S("hpqia"), 0, 4);
- test(S("qanej"), 0, 5);
- test(S("dfkap"), 1, 0);
- test(S("clbao"), 1, 1);
- test(S("ihqrf"), 1, 2);
- test(S("mekdn"), 1, 3);
- test(S("ngtjf"), 1, 4);
- test(S("srdfq"), 2, 0);
- test(S("qkdrs"), 2, 1);
- test(S("ikcrq"), 2, 2);
- test(S("cdaih"), 2, 3);
- test(S("dmajb"), 4, 0);
- test(S("karth"), 4, 1);
- test(S("lhcdo"), 5, 0);
- test(S("acbsj"), 6, 0);
- test(S("pbsjikaole"), 0, 0);
- test(S("pcbahntsje"), 0, 1);
- test(S("mprdjbeiak"), 0, 5);
- test(S("fhepcrntko"), 0, 9);
- test(S("eqmpaidtls"), 0, 10);
- test(S("joidhalcmq"), 1, 0);
- test(S("omigsphflj"), 1, 1);
- test(S("kocgbphfji"), 1, 4);
- test(S("onmjekafbi"), 1, 8);
- test(S("fbslrjiqkm"), 1, 9);
- test(S("oqmrjahnkg"), 5, 0);
- test(S("jeidpcmalh"), 5, 1);
- test(S("schfalibje"), 5, 2);
- test(S("crliponbqe"), 5, 4);
- test(S("igdscopqtm"), 5, 5);
- test(S("qngpdkimlc"), 9, 0);
- test(S("thdjgafrlb"), 9, 1);
- test(S("hcjitbfapl"), 10, 0);
- test(S("mgojkldsqh"), 11, 0);
- test(S("gfshlcmdjreqipbontak"), 0, 0);
- test(S("nadkhpfemgclosibtjrq"), 0, 1);
- test(S("nkodajteqplrbifhmcgs"), 0, 10);
- test(S("ofdrqmkeblthacpgijsn"), 0, 19);
- test(S("gbmetiprqdoasckjfhln"), 0, 20);
- test(S("bdfjqgatlksriohemnpc"), 1, 0);
- test(S("crnklpmegdqfiashtojb"), 1, 1);
- test(S("ejqcnahdrkfsmptilgbo"), 1, 9);
- test(S("jsbtafedocnirgpmkhql"), 1, 18);
- test(S("prqgnlbaejsmkhdctoif"), 1, 19);
- test(S("qnmodrtkebhpasifgcjl"), 10, 0);
- test(S("pejafmnokrqhtisbcdgl"), 10, 1);
- test(S("cpebqsfmnjdolhkratgi"), 10, 5);
- test(S("odnqkgijrhabfmcestlp"), 10, 9);
- test(S("lmofqdhpkibagnrcjste"), 10, 10);
- test(S("lgjqketopbfahrmnsicd"), 19, 0);
- test(S("ktsrmnqagdecfhijpobl"), 19, 1);
- test(S("lsaijeqhtrbgcdmpfkno"), 20, 0);
- test(S("dplqartnfgejichmoskb"), 21, 0);
- }
+ test_string<std::string>();
#if TEST_STD_VER >= 11
- {
- typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
- test(S(""), 0, 0);
- test(S(""), 1, 0);
- test(S("pniot"), 0, 0);
- test(S("htaob"), 0, 1);
- test(S("fodgq"), 0, 2);
- test(S("hpqia"), 0, 4);
- test(S("qanej"), 0, 5);
- test(S("dfkap"), 1, 0);
- test(S("clbao"), 1, 1);
- test(S("ihqrf"), 1, 2);
- test(S("mekdn"), 1, 3);
- test(S("ngtjf"), 1, 4);
- test(S("srdfq"), 2, 0);
- test(S("qkdrs"), 2, 1);
- test(S("ikcrq"), 2, 2);
- test(S("cdaih"), 2, 3);
- test(S("dmajb"), 4, 0);
- test(S("karth"), 4, 1);
- test(S("lhcdo"), 5, 0);
- test(S("acbsj"), 6, 0);
- test(S("pbsjikaole"), 0, 0);
- test(S("pcbahntsje"), 0, 1);
- test(S("mprdjbeiak"), 0, 5);
- test(S("fhepcrntko"), 0, 9);
- test(S("eqmpaidtls"), 0, 10);
- test(S("joidhalcmq"), 1, 0);
- test(S("omigsphflj"), 1, 1);
- test(S("kocgbphfji"), 1, 4);
- test(S("onmjekafbi"), 1, 8);
- test(S("fbslrjiqkm"), 1, 9);
- test(S("oqmrjahnkg"), 5, 0);
- test(S("jeidpcmalh"), 5, 1);
- test(S("schfalibje"), 5, 2);
- test(S("crliponbqe"), 5, 4);
- test(S("igdscopqtm"), 5, 5);
- test(S("qngpdkimlc"), 9, 0);
- test(S("thdjgafrlb"), 9, 1);
- test(S("hcjitbfapl"), 10, 0);
- test(S("mgojkldsqh"), 11, 0);
- test(S("gfshlcmdjreqipbontak"), 0, 0);
- test(S("nadkhpfemgclosibtjrq"), 0, 1);
- test(S("nkodajteqplrbifhmcgs"), 0, 10);
- test(S("ofdrqmkeblthacpgijsn"), 0, 19);
- test(S("gbmetiprqdoasckjfhln"), 0, 20);
- test(S("bdfjqgatlksriohemnpc"), 1, 0);
- test(S("crnklpmegdqfiashtojb"), 1, 1);
- test(S("ejqcnahdrkfsmptilgbo"), 1, 9);
- test(S("jsbtafedocnirgpmkhql"), 1, 18);
- test(S("prqgnlbaejsmkhdctoif"), 1, 19);
- test(S("qnmodrtkebhpasifgcjl"), 10, 0);
- test(S("pejafmnokrqhtisbcdgl"), 10, 1);
- test(S("cpebqsfmnjdolhkratgi"), 10, 5);
- test(S("odnqkgijrhabfmcestlp"), 10, 9);
- test(S("lmofqdhpkibagnrcjste"), 10, 10);
- test(S("lgjqketopbfahrmnsicd"), 19, 0);
- test(S("ktsrmnqagdecfhijpobl"), 19, 1);
- test(S("lsaijeqhtrbgcdmpfkno"), 20, 0);
- test(S("dplqartnfgejichmoskb"), 21, 0);
- }
+ test_string<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>();
#endif
return true;
diff --git a/libcxx/test/std/strings/basic.string/string.ops/string_substr/substr_rvalue.pass.cpp b/libcxx/test/std/strings/basic.string/string.ops/string_substr/substr_rvalue.pass.cpp
new file mode 100644
index 0000000000000..13019ae351077
--- /dev/null
+++ b/libcxx/test/std/strings/basic.string/string.ops/string_substr/substr_rvalue.pass.cpp
@@ -0,0 +1,103 @@
+//===----------------------------------------------------------------------===//
+//
+// 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, c++20
+
+// <string>
+
+// constexpr basic_string substr(size_type pos = 0, size_type n = npos) &&;
+
+#include <algorithm>
+#include <string>
+
+#include "constexpr_char_traits.h"
+#include "make_string.h"
+#include "min_allocator.h"
+#include "test_allocator.h"
+
+#define STR(string) MAKE_CSTRING(typename S::value_type, string)
+
+constexpr struct should_throw_exception_t {
+} should_throw_exception;
+
+template <class S>
+constexpr void test(S orig, size_t pos, ptr
diff _t n, S expected) {
+ S str = std::move(orig).substr(pos, n);
+ LIBCPP_ASSERT(orig.__invariants());
+ LIBCPP_ASSERT(str.__invariants());
+ assert(str == expected);
+}
+
+template <class S>
+constexpr void test(S orig, size_t pos, ptr
diff _t n, should_throw_exception_t) {
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ if (!std::is_constant_evaluated()) {
+ try {
+ S str = std::move(orig).substr(pos, n);
+ assert(false);
+ } catch (const std::out_of_range&) {
+ }
+ }
+#else
+ (void)orig;
+ (void)pos;
+ (void)n;
+#endif
+}
+
+template <class S>
+constexpr void test_string() {
+ test<S>(STR(""), 0, 0, STR(""));
+ test<S>(STR(""), 0, 1, STR(""));
+ test<S>(STR(""), 1, 0, should_throw_exception);
+ test<S>(STR(""), 1, 1, should_throw_exception);
+ test<S>(STR("short string"), 0, 1, STR("s"));
+ test<S>(STR("short string"), 5, 5, STR(" stri"));
+ test<S>(STR("short string"), 12, 5, STR(""));
+ test<S>(STR("short string"), 13, 5, should_throw_exception);
+ test<S>(STR("long long string so no SSO"), 0, 0, STR(""));
+ test<S>(STR("long long string so no SSO"), 0, 10, STR("long long "));
+ test<S>(STR("long long string so no SSO"), 10, 10, STR("string so "));
+ test<S>(STR("long long string so no SSO"), 20, 10, STR("no SSO"));
+ test<S>(STR("long long string so no SSO"), 26, 10, STR(""));
+ test<S>(STR("long long string so no SSO"), 27, 0, should_throw_exception);
+}
+
+template <class CharT, class CharTraits>
+constexpr void test_allocators() {
+ test_string<std::basic_string<CharT, CharTraits, std::allocator<CharT>>>();
+ test_string<std::basic_string<CharT, CharTraits, min_allocator<CharT>>>();
+ test_string<std::basic_string<CharT, CharTraits, test_allocator<CharT>>>();
+}
+
+template <class CharT>
+constexpr void test_char_traits() {
+ test_allocators<CharT, std::char_traits<CharT>>();
+ test_allocators<CharT, constexpr_char_traits<CharT>>();
+}
+
+constexpr bool test() {
+ test_char_traits<char>();
+ test_char_traits<char16_t>();
+ test_char_traits<char32_t>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+ test_char_traits<wchar_t>();
+#endif
+#ifndef TEST_HAS_NO_CHAR8_T
+ test_char_traits<char8_t>();
+#endif
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/support/count_new.h b/libcxx/test/support/count_new.h
index aadebe444708f..645062a01446d 100644
--- a/libcxx/test/support/count_new.h
+++ b/libcxx/test/support/count_new.h
@@ -472,6 +472,40 @@ struct DisableAllocationGuard {
DisableAllocationGuard& operator=(DisableAllocationGuard const&);
};
+#if TEST_STD_VER >= 20
+
+struct ConstexprDisableAllocationGuard {
+ TEST_CONSTEXPR_CXX14 explicit ConstexprDisableAllocationGuard(bool disable = true) : m_disabled(disable)
+ {
+ if (!TEST_IS_CONSTANT_EVALUATED) {
+ // Don't re-disable if already disabled.
+ if (globalMemCounter.disable_allocations == true) m_disabled = false;
+ if (m_disabled) globalMemCounter.disableAllocations();
+ } else {
+ m_disabled = false;
+ }
+ }
+
+ TEST_CONSTEXPR_CXX14 void release() {
+ if (!TEST_IS_CONSTANT_EVALUATED) {
+ if (m_disabled) globalMemCounter.enableAllocations();
+ m_disabled = false;
+ }
+ }
+
+ TEST_CONSTEXPR_CXX20 ~ConstexprDisableAllocationGuard() {
+ release();
+ }
+
+private:
+ bool m_disabled;
+
+ ConstexprDisableAllocationGuard(ConstexprDisableAllocationGuard const&);
+ ConstexprDisableAllocationGuard& operator=(ConstexprDisableAllocationGuard const&);
+};
+
+#endif
+
struct RequireAllocationGuard {
explicit RequireAllocationGuard(std::size_t RequireAtLeast = 1)
: m_req_alloc(RequireAtLeast),
diff --git a/libcxx/test/support/make_string.h b/libcxx/test/support/make_string.h
index 00c2a48e3d004..728b6540abe07 100644
--- a/libcxx/test/support/make_string.h
+++ b/libcxx/test/support/make_string.h
@@ -89,7 +89,7 @@ struct MultiStringType {
// This helper is used in unit tests to make them generic. The input should be
// valid ASCII which means the input is also valid UTF-8.
#define MAKE_CSTRING(CharT, Str) \
- MKSTR(Str).as_ptr((const CharT*)0)
+ MKSTR(Str).as_ptr(static_cast<const CharT*>(nullptr))
// Like MAKE_CSTRING but makes a basic_string<CharT>. Embedded nulls are OK.
#define MAKE_STRING(CharT, Str) \
More information about the libcxx-commits
mailing list