Skip to content

Commit

Permalink
[libc++] Implement P2438R2 (std::string::substr() &&)
Browse files Browse the repository at this point in the history
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
  • Loading branch information
philnik777 committed Nov 2, 2022
1 parent 001d186 commit 29378ab
Show file tree
Hide file tree
Showing 10 changed files with 543 additions and 136 deletions.
1 change: 1 addition & 0 deletions libcxx/docs/ReleaseNotes.rst
Expand Up @@ -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
-----------------------------
Expand Down
2 changes: 1 addition & 1 deletion libcxx/docs/Status/Cxx2bPapers.csv
Expand Up @@ -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","",""
Expand Down
65 changes: 54 additions & 11 deletions libcxx/include/string
Expand Up @@ -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>
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
@@ -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");
}
}
Expand Up @@ -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');
Expand Down

0 comments on commit 29378ab

Please sign in to comment.