Skip to content

WIP [libc++][string] P3044R2: sub-string_view from string #147095

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions libcxx/include/string
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,8 @@ public:
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
constexpr basic_string_view<charT, traits> subview(size_type pos = 0,
size_type n = npos) const; // since C++26
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
Expand Down Expand Up @@ -1745,6 +1747,13 @@ public:
}
# endif

# if _LIBCPP_STD_VER >= 26
_LIBCPP_HIDE_FROM_ABI constexpr basic_string_view<_CharT, _Traits>
subview(size_type __pos = 0, size_type __n = npos) const {
return basic_string_view<_CharT, _Traits>(*this).subview(__pos, __n);
}
# endif

_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void swap(basic_string& __str)
# if _LIBCPP_STD_VER >= 14
_NOEXCEPT;
Expand Down
8 changes: 8 additions & 0 deletions libcxx/include/string_view
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ namespace std {
size_type copy(charT* s, size_type n, size_type pos = 0) const; // constexpr in C++20

constexpr basic_string_view substr(size_type pos = 0, size_type n = npos) const;
constexpr basic_string_view subview(size_type pos = 0,
size_type n = npos) const; // freestanding-deleted, since C++26
constexpr int compare(basic_string_view s) const noexcept;
constexpr int compare(size_type pos1, size_type n1, basic_string_view s) const;
constexpr int compare(size_type pos1, size_type n1,
Expand Down Expand Up @@ -465,6 +467,12 @@ public:
: basic_string_view(__assume_valid(), data() + __pos, std::min(__n, size() - __pos));
}

# if _LIBCPP_STD_VER >= 26
_LIBCPP_HIDE_FROM_ABI constexpr basic_string_view subview(size_type __pos = 0, size_type __n = npos) const {
return this->substr(__pos, __n);
}
# endif

_LIBCPP_CONSTEXPR_SINCE_CXX14 int compare(basic_string_view __sv) const _NOEXCEPT {
size_type __rlen = std::min(size(), __sv.size());
int __retval = _Traits::compare(data(), __sv.data(), __rlen);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// REQUIRES: std-at-least-c++26

// <string>

// constexpr basic_string_view<_CharT, _Traits> subview(size_type __pos = 0, size_type __n = npos) const;

#include <cassert>
#include <string>

constexpr bool test() {
std::string s{"Hello cruel world!"};
auto sub = s.subview(6);
assert(sub == "cruel world!");
auto subsub = sub.subview(0, 5);
assert(subsub == "cruel");

return true;
}

int main(int, char**) {
test();
static_assert(test());

return 0;
}
152 changes: 92 additions & 60 deletions libcxx/test/std/strings/string.view/string.view.ops/substr.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
// <string_view>

// constexpr basic_string_view substr(size_type pos = 0, size_type n = npos) const;
// constexpr basic_string_view subview(size_type pos = 0,
// size_type n = npos) const; // freestanding-deleted

// subview is alternative name of substr

// Throws: out_of_range if pos > size().
// Effects: Determines the effective length rlen of the string to reference as the smaller of n and size() - pos.
Expand All @@ -25,15 +29,21 @@
#include "test_macros.h"

template <typename CharT>
void test1(std::basic_string_view<CharT> sv, std::size_t n, size_t pos) {
struct Test {
typedef std::basic_string_view<CharT> (std::basic_string_view<CharT>::*Sub)(
typename std::basic_string_view<CharT>::size_type, typename std::basic_string_view<CharT>::size_type) const;
};

template <typename CharT, typename Test<CharT>::Sub TestSub>
void testDetail(std::basic_string_view<CharT> sv, std::size_t n, size_t pos) {
std::basic_string_view<CharT> sv1;
#ifdef TEST_HAS_NO_EXCEPTIONS
if (pos > sv.size())
return; // would throw if exceptions were enabled
sv1 = sv.substr(pos, n);
sv1 = (sv.*TestSub)(pos, n);
#else
try {
sv1 = sv.substr(pos, n);
sv1 = (sv.*TestSub)(pos, n);
assert(pos <= sv.size());
} catch (const std::out_of_range&) {
assert(pos > sv.size());
Expand All @@ -46,79 +56,101 @@ void test1(std::basic_string_view<CharT> sv, std::size_t n, size_t pos) {
assert(sv[pos + i] == sv1[i]);
}

template <typename CharT>
void test(const CharT* s) {
typedef std::basic_string_view<CharT> string_view_t;
template <typename CharT, typename Test<CharT>::Sub TestSub>
void testCases(const CharT* s) {
std::basic_string_view<CharT> sv(s);

string_view_t sv1(s);
testDetail<CharT, TestSub>(sv, 0, 0);
testDetail<CharT, TestSub>(sv, 1, 0);
testDetail<CharT, TestSub>(sv, 20, 0);
testDetail<CharT, TestSub>(sv, sv.size(), 0);

test1(sv1, 0, 0);
test1(sv1, 1, 0);
test1(sv1, 20, 0);
test1(sv1, sv1.size(), 0);
testDetail<CharT, TestSub>(sv, 100, 3);

test1(sv1, 0, 3);
test1(sv1, 2, 3);
test1(sv1, 100, 3);
testDetail<CharT, TestSub>(sv, 0, std::basic_string_view<CharT>::npos);
testDetail<CharT, TestSub>(sv, 2, std::basic_string_view<CharT>::npos);
testDetail<CharT, TestSub>(sv, sv.size(), std::basic_string_view<CharT>::npos);

test1(sv1, 0, string_view_t::npos);
test1(sv1, 2, string_view_t::npos);
test1(sv1, sv1.size(), string_view_t::npos);
testDetail<CharT, TestSub>(sv, sv.size() + 1, 0);
testDetail<CharT, TestSub>(sv, sv.size() + 1, 1);
testDetail<CharT, TestSub>(sv, sv.size() + 1, std::basic_string_view<CharT>::npos);
}

test1(sv1, sv1.size() + 1, 0);
test1(sv1, sv1.size() + 1, 1);
test1(sv1, sv1.size() + 1, string_view_t::npos);
template <typename CharT>
void testSubs(const CharT* s) {
testCases<CharT, &std::basic_string_view<CharT>::substr>(s);
#if TEST_STD_VER >= 26
testCases<CharT, &std::basic_string_view<CharT>::subview>(s);
#endif // TEST_STD_VER >= 26
}

int main(int, char**) {
test("ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE");
test("ABCDE");
test("a");
test("");
void test() {
testSubs("ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE");
testSubs("ABCDE");
testSubs("a");
testSubs("");

#ifndef TEST_HAS_NO_WIDE_CHARACTERS
test(L"ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE");
test(L"ABCDE");
test(L"a");
test(L"");
testSubs(
L"ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE");
testSubs(L"ABCDE");
testSubs(L"a");
testSubs(L"");
#endif

#if TEST_STD_VER >= 11
test(u"ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE");
test(u"ABCDE");
test(u"a");
test(u"");

test(U"ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE");
test(U"ABCDE");
test(U"a");
test(U"");
testSubs(
u"ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE");
testSubs(u"ABCDE");
testSubs(u"a");
testSubs(u"");

testSubs(
U"ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE");
testSubs(U"ABCDE");
testSubs(U"a");
testSubs(U"");
#endif
}

#if TEST_STD_VER >= 14
template <typename Test<char>::Sub TestSub>
constexpr void testConstexprDetail() {
constexpr std::string_view sv{"ABCDE", 5};
{
constexpr std::string_view sv2 = (sv.*TestSub)(0, 3);

static_assert(sv2.size() == 3, "");
static_assert(sv2[0] == 'A', "");
static_assert(sv2[1] == 'B', "");
static_assert(sv2[2] == 'C', "");
}

#if TEST_STD_VER > 11
{
constexpr std::string_view sv1{"ABCDE", 5};

{
constexpr std::string_view sv2 = sv1.substr(0, 3);
static_assert(sv2.size() == 3, "");
static_assert(sv2[0] == 'A', "");
static_assert(sv2[1] == 'B', "");
static_assert(sv2[2] == 'C', "");
}

{
constexpr std::string_view sv2 = sv1.substr(3, 0);
static_assert(sv2.size() == 0, "");
}

{
constexpr std::string_view sv2 = sv1.substr(3, 3);
static_assert(sv2.size() == 2, "");
static_assert(sv2[0] == 'D', "");
static_assert(sv2[1] == 'E', "");
}
constexpr std::string_view sv2 = (sv.*TestSub)(3, 0);
static_assert(sv2.size() == 0, "");
}

{
constexpr std::string_view sv2 = (sv.*TestSub)(3, 3);
static_assert(sv2.size() == 2, "");
static_assert(sv2[0] == 'D', "");
static_assert(sv2[1] == 'E', "");
}
}

void test_constexpr() {
testConstexprDetail<&std::string_view::substr>();
# if TEST_STD_VER >= 26
testConstexprDetail<&std::string_view::subview>();
# endif
}
#endif

int main(int, char**) {
test();
#if TEST_STD_VER >= 14
test_constexpr();
#endif

return 0;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// REQUIRES: std-at-least-c++26

// <string_view>

// constexpr basic_string_view subview(size_type pos = 0,
// size_type n = npos) const; // freestanding-deleted

int main(int, char**) {
// This test is intentionally empty because subview is an alias for substr
// and is tested in substr.pass.cpp.
Comment on lines +17 to +18
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like we don't need this file.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure what the current practice about function aliases is. Normally we want a test file per function. This one is to tell the user what to look at. Are there any similar cases in the library?

return 0;
}
Loading