1baf6f918Svarconst //===----------------------------------------------------------------------===// 2baf6f918Svarconst // 3baf6f918Svarconst // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4baf6f918Svarconst // See https://llvm.org/LICENSE.txt for license information. 5baf6f918Svarconst // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6baf6f918Svarconst // 7baf6f918Svarconst //===----------------------------------------------------------------------===// 8baf6f918Svarconst 9baf6f918Svarconst // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 10baf6f918Svarconst 11baf6f918Svarconst // template<container-compatible-range<charT> R> 12baf6f918Svarconst // constexpr basic_string(from_range_t, R&& rg, const Allocator& a = Allocator()); // since C++23 13baf6f918Svarconst 14baf6f918Svarconst #include <algorithm> 15*80097a1fSA. Jiang #include <sstream> 16baf6f918Svarconst #include <string> 17baf6f918Svarconst #include <utility> 18baf6f918Svarconst #include <vector> 19baf6f918Svarconst 20baf6f918Svarconst #include "../../../containers/from_range_helpers.h" 21baf6f918Svarconst #include "../../../containers/sequences/from_range_sequence_containers.h" 22baf6f918Svarconst #include "test_macros.h" 239ed20568STacet #include "asan_testing.h" 24baf6f918Svarconst 25baf6f918Svarconst template <class Container, class Range, class Alloc> 26a40bada9SBrendan Emery concept StringHasFromRangeAllocCtr = 27a40bada9SBrendan Emery requires(Range&& range, const Alloc& alloc) { Container(std::from_range, std::forward<Range>(range), alloc); }; 28baf6f918Svarconst 29baf6f918Svarconst constexpr bool test_constraints() { 30baf6f918Svarconst // (from_range, range) 31baf6f918Svarconst // 32baf6f918Svarconst // Input range with the same value type. 33baf6f918Svarconst static_assert(HasFromRangeCtr<std::string, InputRange<char>>); 34baf6f918Svarconst // Input range with a convertible value type. 35baf6f918Svarconst static_assert(HasFromRangeCtr<std::string, InputRange<int>>); 36baf6f918Svarconst // Input range with a non-convertible value type. 37baf6f918Svarconst static_assert(!HasFromRangeCtr<std::string, InputRange<Empty>>); 38baf6f918Svarconst // Not an input range. 39baf6f918Svarconst static_assert(!HasFromRangeCtr<std::string, InputRangeNotDerivedFrom>); 40baf6f918Svarconst static_assert(!HasFromRangeCtr<std::string, InputRangeNotIndirectlyReadable>); 41baf6f918Svarconst static_assert(!HasFromRangeCtr<std::string, InputRangeNotInputOrOutputIterator>); 42baf6f918Svarconst 43baf6f918Svarconst // (from_range, range, alloc) 44baf6f918Svarconst // 45baf6f918Svarconst // Input range with the same value type. 46baf6f918Svarconst using Alloc = test_allocator<char>; 47baf6f918Svarconst using StringWithAlloc = std::basic_string<char, std::char_traits<char>, Alloc>; 48baf6f918Svarconst static_assert(StringHasFromRangeAllocCtr<StringWithAlloc, InputRange<char>, Alloc>); 49baf6f918Svarconst // Input range with a convertible value type. 50baf6f918Svarconst static_assert(StringHasFromRangeAllocCtr<StringWithAlloc, InputRange<int>, Alloc>); 51baf6f918Svarconst // Input range with a non-convertible value type. 52baf6f918Svarconst static_assert(!StringHasFromRangeAllocCtr<StringWithAlloc, InputRange<Empty>, Alloc>); 53baf6f918Svarconst // Not an input range. 54baf6f918Svarconst static_assert(!StringHasFromRangeAllocCtr<StringWithAlloc, InputRangeNotDerivedFrom, Alloc>); 55baf6f918Svarconst static_assert(!StringHasFromRangeAllocCtr<StringWithAlloc, InputRangeNotIndirectlyReadable, Alloc>); 56baf6f918Svarconst static_assert(!StringHasFromRangeAllocCtr<StringWithAlloc, InputRangeNotInputOrOutputIterator, Alloc>); 57baf6f918Svarconst // Not an allocator. 58baf6f918Svarconst static_assert(!StringHasFromRangeAllocCtr<StringWithAlloc, InputRange<char>, Empty>); 59baf6f918Svarconst 60baf6f918Svarconst return true; 61baf6f918Svarconst } 62baf6f918Svarconst 63a40bada9SBrendan Emery template <class Iter, class Sent, class Alloc> 64baf6f918Svarconst constexpr void test_with_input(std::vector<char> input) { 65baf6f918Svarconst { // (range) 66f73050e7SLouis Dionne std::ranges::subrange in(Iter(input.data()), Sent(Iter(input.data() + input.size()))); 67baf6f918Svarconst std::string c(std::from_range, in); 68baf6f918Svarconst 69baf6f918Svarconst LIBCPP_ASSERT(c.__invariants()); 70baf6f918Svarconst assert(c.size() == static_cast<std::size_t>(std::distance(c.begin(), c.end()))); 71f73050e7SLouis Dionne assert(std::ranges::equal(input, c)); 729ed20568STacet LIBCPP_ASSERT(is_string_asan_correct(c)); 73baf6f918Svarconst } 74baf6f918Svarconst 75baf6f918Svarconst { // (range, allocator) 76f73050e7SLouis Dionne std::ranges::subrange in(Iter(input.data()), Sent(Iter(input.data() + input.size()))); 77baf6f918Svarconst Alloc alloc; 78baf6f918Svarconst std::basic_string<char, std::char_traits<char>, Alloc> c(std::from_range, in, alloc); 79baf6f918Svarconst 80baf6f918Svarconst LIBCPP_ASSERT(c.__invariants()); 81baf6f918Svarconst assert(c.get_allocator() == alloc); 82baf6f918Svarconst assert(c.size() == static_cast<std::size_t>(std::distance(c.begin(), c.end()))); 83f73050e7SLouis Dionne assert(std::ranges::equal(input, c)); 849ed20568STacet LIBCPP_ASSERT(is_string_asan_correct(c)); 85baf6f918Svarconst } 86*80097a1fSA. Jiang 87*80097a1fSA. Jiang { // Ensure input-only sized ranges are accepted. 88*80097a1fSA. Jiang using input_iter = cpp20_input_iterator<const char*>; 89*80097a1fSA. Jiang const char in[]{'q', 'w', 'e', 'r'}; 90*80097a1fSA. Jiang std::string s(std::from_range, std::views::counted(input_iter{std::ranges::begin(in)}, std::ranges::ssize(in))); 91*80097a1fSA. Jiang assert(s == "qwer"); 92*80097a1fSA. Jiang } 93baf6f918Svarconst } 94baf6f918Svarconst 95baf6f918Svarconst void test_string_exception_safety_throwing_allocator() { 96baf6f918Svarconst #if !defined(TEST_HAS_NO_EXCEPTIONS) 97baf6f918Svarconst try { 98baf6f918Svarconst ThrowingAllocator<char> alloc; 99baf6f918Svarconst 100baf6f918Svarconst globalMemCounter.reset(); 101baf6f918Svarconst // Note: the input string must be long enough to prevent SSO, otherwise the allocator won't be used. 102baf6f918Svarconst std::basic_string<char, std::char_traits<char>, ThrowingAllocator<char>> c( 103baf6f918Svarconst std::from_range, std::vector<char>(64, 'A'), alloc); 104baf6f918Svarconst assert(false); // The constructor call should throw. 105baf6f918Svarconst 106baf6f918Svarconst } catch (int) { 107baf6f918Svarconst assert(globalMemCounter.new_called == globalMemCounter.delete_called); 108baf6f918Svarconst } 109baf6f918Svarconst #endif 110baf6f918Svarconst } 111baf6f918Svarconst 112baf6f918Svarconst constexpr bool test_inputs() { 113baf6f918Svarconst for_all_iterators_and_allocators<char>([]<class Iter, class Sent, class Alloc>() { 114baf6f918Svarconst // Shorter input -- SSO. 115baf6f918Svarconst test_with_input<Iter, Sent, Alloc>({'a', 'b', 'c', 'd', 'e'}); 116baf6f918Svarconst // Longer input -- no SSO. 117baf6f918Svarconst test_with_input<Iter, Sent, Alloc>(std::vector<char>(64, 'A')); 118baf6f918Svarconst // Empty input. 119baf6f918Svarconst test_with_input<Iter, Sent, Alloc>({}); 120baf6f918Svarconst // Single-element input. 121baf6f918Svarconst test_with_input<Iter, Sent, Alloc>({'a'}); 122baf6f918Svarconst }); 123baf6f918Svarconst 124baf6f918Svarconst return true; 125baf6f918Svarconst } 126baf6f918Svarconst 127*80097a1fSA. Jiang #ifndef TEST_HAS_NO_LOCALIZATION 128*80097a1fSA. Jiang void test_counted_istream_view() { 129*80097a1fSA. Jiang std::istringstream is{"qwert"}; 130*80097a1fSA. Jiang auto vals = std::views::istream<char>(is); 131*80097a1fSA. Jiang std::string s(std::from_range, std::views::counted(vals.begin(), 3)); 132*80097a1fSA. Jiang assert(s == "qwe"); 133*80097a1fSA. Jiang } 134*80097a1fSA. Jiang #endif 135*80097a1fSA. Jiang 136baf6f918Svarconst int main(int, char**) { 137baf6f918Svarconst test_inputs(); 138baf6f918Svarconst static_assert(test_inputs()); 139baf6f918Svarconst 140baf6f918Svarconst static_assert(test_constraints()); 141baf6f918Svarconst 142baf6f918Svarconst // Note: `test_exception_safety_throwing_copy` doesn't apply because copying a `char` cannot throw. 143baf6f918Svarconst test_string_exception_safety_throwing_allocator(); 144baf6f918Svarconst 145*80097a1fSA. Jiang #ifndef TEST_HAS_NO_LOCALIZATION 146*80097a1fSA. Jiang test_counted_istream_view(); 147*80097a1fSA. Jiang #endif 148*80097a1fSA. Jiang 149baf6f918Svarconst return 0; 150baf6f918Svarconst } 151