Implement P1989R2 which adds a range constructor for `string_view`.
Adjust `operator/=` in `path` to avoid atomic constraints caching issue
getting provoked from this PR.
Add defaulted template argument to `string_view`'s "sufficient
overloads" to avoid mangling issues in `clang-cl` builds. It is a
MSVC mangling bug that this works around.
Differential Revision: https://reviews.llvm.org/D113161
"`P1518R2 <https://wg21.link/P1518R2>`__","LWG","Stop overconstraining allocators in container deduction guides","June 2021","|Complete|","13.0"
"`P1659R3 <https://wg21.link/P1659R3>`__","LWG","starts_with and ends_with","June 2021","",""
"`P1951R1 <https://wg21.link/P1951R1>`__","LWG","Default Arguments for pair Forwarding Constructor","June 2021","|Complete|","14.0"
-"`P1989R2 <https://wg21.link/P1989R2>`__","LWG","Range constructor for std::string_view","June 2021","",""
+"`P1989R2 <https://wg21.link/P1989R2>`__","LWG","Range constructor for std::string_view","June 2021","|Complete|","14.0"
"`P2136R3 <https://wg21.link/P2136R3>`__","LWG","invoke_r","June 2021","",""
"`P2166R1 <https://wg21.link/P2166R1>`__","LWG","A Proposal to Prohibit std::basic_string and std::basic_string_view construction from nullptr","June 2021","|Complete|","13.0"
"","","","","",""
auto __p_root_name = __p.__root_name();
auto __p_root_name_size = __p_root_name.size();
if (__p.is_absolute() ||
- (!__p_root_name.empty() && __p_root_name != root_name())) {
+ (!__p_root_name.empty() && __p_root_name != __string_view(root_name().__pn_))) {
__pn_ = __p.__pn_;
return *this;
}
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
+ template <class Range>
+ constexpr basic_string_view(Range&& r); // C++23
// 7.4, basic_string_view iterator support
constexpr const_iterator begin() const noexcept;
// basic_string_view deduction guides
template<class It, class End>
basic_string_view(It, End) -> basic_string_view<iter_value_t<It>>; // C++20
+ template<class Range>
+ basic_string_view(Range&&) -> basic_string_view<ranges::range_value_t<Range>>; // C++23
// 7.11, Hash support
template <class T> struct hash;
#include <__config>
#include <__debug>
+#include <__ranges/concepts.h>
+#include <__ranges/data.h>
#include <__ranges/enable_borrowed_range.h>
#include <__ranges/enable_view.h>
+#include <__ranges/size.h>
#include <__string>
#include <algorithm>
#include <compare>
#include <iterator>
#include <limits>
#include <stdexcept>
+#include <type_traits>
#include <version>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
}
#endif
+#if _LIBCPP_STD_VER > 20 && !defined(_LIBCPP_HAS_NO_RANGES)
+ template <class _Range>
+ requires (
+ !is_same_v<remove_cvref_t<_Range>, basic_string_view> &&
+ ranges::contiguous_range<_Range> &&
+ ranges::sized_range<_Range> &&
+ is_same_v<ranges::range_value_t<_Range>, _CharT> &&
+ !is_convertible_v<_Range, const _CharT*> &&
+ (!requires(remove_cvref_t<_Range>& d) {
+ d.operator _VSTD::basic_string_view<_CharT, _Traits>();
+ }) &&
+ (!requires {
+ typename remove_reference_t<_Range>::traits_type;
+ } || is_same_v<typename remove_reference_t<_Range>::traits_type, _Traits>)
+ )
+ constexpr _LIBCPP_HIDE_FROM_ABI
+ basic_string_view(_Range&& __r) : __data(ranges::data(__r)), __size(ranges::size(__r)) {}
+#endif
+
_LIBCPP_CONSTEXPR _LIBCPP_INLINE_VISIBILITY
basic_string_view(const _CharT* __s)
: __data(__s), __size(_VSTD::__char_traits_length_checked<_Traits>(__s)) {}
basic_string_view(_It, _End) -> basic_string_view<iter_value_t<_It>>;
#endif
+
+#if _LIBCPP_STD_VER > 20 && !defined(_LIBCPP_HAS_NO_RANGES)
+template <ranges::contiguous_range _Range>
+ basic_string_view(_Range) -> basic_string_view<ranges::range_value_t<_Range>>;
+#endif
+
// [string.view.comparison]
// operator ==
template<class _CharT, class _Traits>
return __lhs.compare(__rhs) == 0;
}
-template<class _CharT, class _Traits>
+// The dummy default template parameters are used to work around a MSVC issue with mangling, see VSO-409326 for details.
+// This applies to the other sufficient overloads below for the other comparison operators.
+template<class _CharT, class _Traits, int = 1>
_LIBCPP_CONSTEXPR_AFTER_CXX11 _LIBCPP_INLINE_VISIBILITY
bool operator==(basic_string_view<_CharT, _Traits> __lhs,
typename common_type<basic_string_view<_CharT, _Traits> >::type __rhs) _NOEXCEPT
return __lhs.compare(__rhs) == 0;
}
-template<class _CharT, class _Traits>
+template<class _CharT, class _Traits, int = 2>
_LIBCPP_CONSTEXPR_AFTER_CXX11 _LIBCPP_INLINE_VISIBILITY
bool operator==(typename common_type<basic_string_view<_CharT, _Traits> >::type __lhs,
basic_string_view<_CharT, _Traits> __rhs) _NOEXCEPT
return __lhs.compare(__rhs) != 0;
}
-template<class _CharT, class _Traits>
+template<class _CharT, class _Traits, int = 1>
_LIBCPP_CONSTEXPR_AFTER_CXX11 _LIBCPP_INLINE_VISIBILITY
bool operator!=(basic_string_view<_CharT, _Traits> __lhs,
typename common_type<basic_string_view<_CharT, _Traits> >::type __rhs) _NOEXCEPT
return __lhs.compare(__rhs) != 0;
}
-template<class _CharT, class _Traits>
+template<class _CharT, class _Traits, int = 2>
_LIBCPP_CONSTEXPR_AFTER_CXX11 _LIBCPP_INLINE_VISIBILITY
bool operator!=(typename common_type<basic_string_view<_CharT, _Traits> >::type __lhs,
basic_string_view<_CharT, _Traits> __rhs) _NOEXCEPT
return __lhs.compare(__rhs) < 0;
}
-template<class _CharT, class _Traits>
+template<class _CharT, class _Traits, int = 1>
_LIBCPP_CONSTEXPR_AFTER_CXX11 _LIBCPP_INLINE_VISIBILITY
bool operator<(basic_string_view<_CharT, _Traits> __lhs,
typename common_type<basic_string_view<_CharT, _Traits> >::type __rhs) _NOEXCEPT
return __lhs.compare(__rhs) < 0;
}
-template<class _CharT, class _Traits>
+template<class _CharT, class _Traits, int = 2>
_LIBCPP_CONSTEXPR_AFTER_CXX11 _LIBCPP_INLINE_VISIBILITY
bool operator<(typename common_type<basic_string_view<_CharT, _Traits> >::type __lhs,
basic_string_view<_CharT, _Traits> __rhs) _NOEXCEPT
return __lhs.compare(__rhs) > 0;
}
-template<class _CharT, class _Traits>
+template<class _CharT, class _Traits, int = 1>
_LIBCPP_CONSTEXPR_AFTER_CXX11 _LIBCPP_INLINE_VISIBILITY
bool operator>(basic_string_view<_CharT, _Traits> __lhs,
typename common_type<basic_string_view<_CharT, _Traits> >::type __rhs) _NOEXCEPT
return __lhs.compare(__rhs) > 0;
}
-template<class _CharT, class _Traits>
+template<class _CharT, class _Traits, int = 2>
_LIBCPP_CONSTEXPR_AFTER_CXX11 _LIBCPP_INLINE_VISIBILITY
bool operator>(typename common_type<basic_string_view<_CharT, _Traits> >::type __lhs,
basic_string_view<_CharT, _Traits> __rhs) _NOEXCEPT
return __lhs.compare(__rhs) <= 0;
}
-template<class _CharT, class _Traits>
+template<class _CharT, class _Traits, int = 1>
_LIBCPP_CONSTEXPR_AFTER_CXX11 _LIBCPP_INLINE_VISIBILITY
bool operator<=(basic_string_view<_CharT, _Traits> __lhs,
typename common_type<basic_string_view<_CharT, _Traits> >::type __rhs) _NOEXCEPT
return __lhs.compare(__rhs) <= 0;
}
-template<class _CharT, class _Traits>
+template<class _CharT, class _Traits, int = 2>
_LIBCPP_CONSTEXPR_AFTER_CXX11 _LIBCPP_INLINE_VISIBILITY
bool operator<=(typename common_type<basic_string_view<_CharT, _Traits> >::type __lhs,
basic_string_view<_CharT, _Traits> __rhs) _NOEXCEPT
}
-template<class _CharT, class _Traits>
+template<class _CharT, class _Traits, int = 1>
_LIBCPP_CONSTEXPR_AFTER_CXX11 _LIBCPP_INLINE_VISIBILITY
bool operator>=(basic_string_view<_CharT, _Traits> __lhs,
typename common_type<basic_string_view<_CharT, _Traits> >::type __rhs) _NOEXCEPT
return __lhs.compare(__rhs) >= 0;
}
-template<class _CharT, class _Traits>
+template<class _CharT, class _Traits, int = 2>
_LIBCPP_CONSTEXPR_AFTER_CXX11 _LIBCPP_INLINE_VISIBILITY
bool operator>=(typename common_type<basic_string_view<_CharT, _Traits> >::type __lhs,
basic_string_view<_CharT, _Traits> __rhs) _NOEXCEPT
--- /dev/null
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// <string_view>
+
+// template <class Range>
+// constexpr basic_string_view(Range&& range);
+
+#include <string_view>
+#include <array>
+#include <cassert>
+#include <iterator>
+#include <ranges>
+#include <type_traits>
+#include <vector>
+
+#include "constexpr_char_traits.h"
+#include "make_string.h"
+#include "test_iterators.h"
+#include "test_range.h"
+
+template<class CharT>
+constexpr void test() {
+ auto data = MAKE_STRING_VIEW(CharT, "test");
+ std::array<CharT, 4> arr;
+ for(int i = 0; i < 4; ++i) {
+ arr[i] = data[i];
+ }
+ auto sv = std::basic_string_view<CharT>(arr);
+
+ ASSERT_SAME_TYPE(decltype(sv), std::basic_string_view<CharT>);
+ assert(sv.size() == arr.size());
+ assert(sv.data() == arr.data());
+}
+
+constexpr bool test() {
+ test<char>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+ test<wchar_t>();
+#endif
+ test<char8_t>();
+ test<char16_t>();
+ test<char32_t>();
+
+ {
+ struct NonConstConversionOperator {
+ const char* data_ = "test";
+ constexpr const char* begin() const { return data_; }
+ constexpr const char* end() const { return data_ + 4; }
+ constexpr operator std::basic_string_view<char>() { return "NonConstConversionOp"; }
+ };
+
+ NonConstConversionOperator nc;
+ std::string_view sv = nc;
+ assert(sv == "NonConstConversionOp");
+ static_assert(!std::is_constructible_v<std::string_view,
+ const NonConstConversionOperator&>); // conversion operator is non-const
+ }
+
+ {
+ struct ConstConversionOperator {
+ const char* data_ = "test";
+ constexpr const char* begin() const { return data_; }
+ constexpr const char* end() const { return data_ + 4; }
+ constexpr operator std::basic_string_view<char>() const { return "ConstConversionOp"; }
+ };
+ ConstConversionOperator cv;
+ std::basic_string_view<char> sv = cv;
+ assert(sv == "ConstConversionOp");
+ }
+
+ struct DeletedConversionOperator {
+ const char* data_ = "test";
+ constexpr const char* begin() const { return data_; }
+ constexpr const char* end() const { return data_ + 4; }
+ operator std::basic_string_view<char>() = delete;
+ };
+
+ struct DeletedConstConversionOperator {
+ const char* data_ = "test";
+ constexpr const char* begin() const { return data_; }
+ constexpr const char* end() const { return data_ + 4; }
+ operator std::basic_string_view<char>() const = delete;
+ };
+
+ static_assert(std::is_constructible_v<std::string_view, DeletedConversionOperator>);
+ static_assert(std::is_constructible_v<std::string_view, const DeletedConversionOperator>);
+ static_assert(std::is_constructible_v<std::string_view, DeletedConstConversionOperator>);
+ static_assert(std::is_constructible_v<std::string_view, const DeletedConstConversionOperator>);
+
+ // Test that we're not trying to use the type's conversion operator to string_view in the constructor.
+ {
+ const DeletedConversionOperator d;
+ std::basic_string_view<char> csv = d;
+ assert(csv == "test");
+ }
+
+ {
+ DeletedConstConversionOperator dc;
+ std::basic_string_view<char> sv = dc;
+ assert(sv == "test");
+ }
+
+ return true;
+}
+
+static_assert(std::is_constructible_v<std::string_view, std::vector<char>&>);
+static_assert(std::is_constructible_v<std::string_view, const std::vector<char>&>);
+static_assert(std::is_constructible_v<std::string_view, std::vector<char>&&>);
+static_assert(std::is_constructible_v<std::string_view, const std::vector<char>&&>);
+
+using SizedButNotContiguousRange = std::ranges::subrange<random_access_iterator<char*>>;
+static_assert(!std::ranges::contiguous_range<SizedButNotContiguousRange>);
+static_assert(std::ranges::sized_range<SizedButNotContiguousRange>);
+static_assert(!std::is_constructible_v<std::string_view, SizedButNotContiguousRange>);
+
+using ContiguousButNotSizedRange = std::ranges::subrange<contiguous_iterator<char*>, sentinel_wrapper<char*>, std::ranges::subrange_kind::unsized>;
+static_assert(std::ranges::contiguous_range<ContiguousButNotSizedRange>);
+static_assert(!std::ranges::sized_range<ContiguousButNotSizedRange>);
+static_assert(!std::is_constructible_v<std::string_view, ContiguousButNotSizedRange>);
+
+static_assert(!std::is_constructible_v<std::string_view, std::vector<char16_t>>); // different CharT
+
+struct WithStringViewConversionOperator {
+ char* begin() const;
+ char* end() const;
+ operator std::string_view() const { return {}; }
+};
+
+static_assert(std::is_constructible_v<std::string_view, WithStringViewConversionOperator>); // lvalue
+static_assert(std::is_constructible_v<std::string_view, const WithStringViewConversionOperator&>); // const lvalue
+static_assert(std::is_constructible_v<std::string_view, WithStringViewConversionOperator&&>); // rvalue
+
+template <class CharTraits>
+struct WithTraitsType {
+ typename CharTraits::char_type* begin() const;
+ typename CharTraits::char_type* end() const;
+ using traits_type = CharTraits;
+};
+
+using CCT = constexpr_char_traits<char>;
+static_assert(std::is_constructible_v<std::string_view, WithTraitsType<std::char_traits<char>>>);
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+static_assert(std::is_constructible_v<std::wstring_view, WithTraitsType<std::char_traits<wchar_t>>>);
+#endif
+static_assert(std::is_constructible_v<std::basic_string_view<char, CCT>, WithTraitsType<CCT>>);
+static_assert(!std::is_constructible_v<std::string_view, WithTraitsType<CCT>>); // wrong traits type
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+static_assert(!std::is_constructible_v<std::wstring_view, WithTraitsType<std::char_traits<char>>>); // wrong traits type
+#endif
+
+#ifndef TEST_HAS_NO_EXCEPTIONS
+void test_throwing() {
+ struct ThrowingData {
+ char* begin() const { return nullptr; }
+ char* end() const { return nullptr; }
+ char* data() const { throw 42; return nullptr; }
+ };
+ try {
+ ThrowingData x;
+ (void) std::string_view(x);
+ assert(false);
+ } catch (int i) {
+ assert(i == 42);
+ }
+
+ struct ThrowingSize {
+ char* begin() const { return nullptr; }
+ char* end() const { return nullptr; }
+ size_t size() const { throw 42; return 0; }
+ };
+ try {
+ ThrowingSize x;
+ (void) std::string_view(x);
+ assert(false);
+ } catch (int i) {
+ assert(i == 42);
+ }
+}
+#endif
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ test_throwing();
+#endif
+
+ return 0;
+}
+
--- /dev/null
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+
+// <string_view>
+
+// template<class Range>
+// basic_string_view(Range&&) -> basic_string_view<ranges::range_value_t<Range>>; // C++23
+
+#include <string_view>
+#include <cassert>
+
+#include "make_string.h"
+#include "test_iterators.h"
+#include "test_macros.h"
+
+template<class CharT>
+void test() {
+ auto val = MAKE_STRING(CharT, "test");
+ auto sv = std::basic_string_view(val);
+ ASSERT_SAME_TYPE(decltype(sv), std::basic_string_view<CharT>);
+ assert(sv.size() == val.size());
+ assert(sv.data() == val.data());
+}
+
+void test() {
+ test<char>();
+#ifndef TEST_HAS_NO_WIDE_CHARACTERS
+ test<wchar_t>();
+#endif
+ test<char8_t>();
+ test<char16_t>();
+ test<char32_t>();
+ test<char>();
+
+ struct Widget {
+ const char16_t *data_ = u"foo";
+ contiguous_iterator<const char16_t*> begin() const { return contiguous_iterator<const char16_t*>(data_); }
+ contiguous_iterator<const char16_t*> end() const { return contiguous_iterator<const char16_t*>(data_ + 3); }
+ };
+ std::basic_string_view bsv = Widget();
+ ASSERT_SAME_TYPE(decltype(bsv), std::basic_string_view<char16_t>);
+}
+
+int main(int, char**) {
+ test();
+
+ return 0;
+}
+