//===----------------------------------------------------------------------===//
//
// 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_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 "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 = std::basic_string_view<char>(d);
assert(csv == "test");
}
{
DeletedConstConversionOperator dc;
std::basic_string_view<char> sv = std::basic_string_view<char>(dc);
assert(sv == "test");
}
// Different trait types
{
struct OtherTraits : std::char_traits<char> {};
std::basic_string_view<char> sv1{"hello"};
std::basic_string_view<char, OtherTraits> sv2(sv1);
assert(sv1.size() == sv2.size());
assert(sv1.data() == sv2.data());
}
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<contiguous_iterator<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
#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; }
std::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
static_assert(!std::is_convertible_v<std::vector<char>, std::string_view>);
int main(int, char**) {
test();
static_assert(test());
#ifndef TEST_HAS_NO_EXCEPTIONS
test_throwing();
#endif
return 0;
}