diff options
Diffstat (limited to 'libcxx/test/libcxx-03/strings')
7 files changed, 735 insertions, 0 deletions
diff --git a/libcxx/test/libcxx-03/strings/basic.string/sizeof.compile.pass.cpp b/libcxx/test/libcxx-03/strings/basic.string/sizeof.compile.pass.cpp new file mode 100644 index 000000000000..31f1a94c7321 --- /dev/null +++ b/libcxx/test/libcxx-03/strings/basic.string/sizeof.compile.pass.cpp @@ -0,0 +1,145 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// Ensure that we never change the size or alignment of `basic_string` + +#include <cstdint> +#include <iterator> +#include <string> + +#include "test_macros.h" +#include "min_allocator.h" +#include "test_allocator.h" + +template <class T> +class small_pointer { +public: + using value_type = T; + using difference_type = std::int16_t; + using pointer = small_pointer; + using reference = T&; + using iterator_category = std::random_access_iterator_tag; + +private: + std::uint16_t offset; +}; + +template <class T> +class small_iter_allocator { +public: + using value_type = T; + using pointer = small_pointer<T>; + using size_type = std::int16_t; + using difference_type = std::int16_t; + + small_iter_allocator() TEST_NOEXCEPT {} + + template <class U> + small_iter_allocator(small_iter_allocator<U>) TEST_NOEXCEPT {} + + T* allocate(std::size_t n); + void deallocate(T* p, std::size_t); + + friend bool operator==(small_iter_allocator, small_iter_allocator) { return true; } + friend bool operator!=(small_iter_allocator, small_iter_allocator) { return false; } +}; + +template <class CharT> +using min_string = std::basic_string<CharT, std::char_traits<CharT>, min_allocator<CharT> >; + +template <class CharT> +using test_string = std::basic_string<CharT, std::char_traits<CharT>, test_allocator<CharT> >; + +template <class CharT> +using small_string = std::basic_string<CharT, std::char_traits<CharT>, small_iter_allocator<CharT> >; + +#if __SIZE_WIDTH__ == 64 + +static_assert(sizeof(std::string) == 24, ""); +static_assert(sizeof(min_string<char>) == 24, ""); +static_assert(sizeof(test_string<char>) == 32, ""); +static_assert(sizeof(small_string<char>) == 6, ""); + +# ifndef TEST_HAS_NO_WIDE_CHARACTERS +# if __WCHAR_WIDTH__ == 32 +static_assert(sizeof(std::wstring) == 24, ""); +static_assert(sizeof(min_string<wchar_t>) == 24, ""); +static_assert(sizeof(test_string<wchar_t>) == 32, ""); +static_assert(sizeof(small_string<wchar_t>) == 12, ""); +# elif __WCHAR_WIDTH__ == 16 +static_assert(sizeof(std::wstring) == 24, ""); +static_assert(sizeof(min_string<wchar_t>) == 24, ""); +static_assert(sizeof(test_string<wchar_t>) == 32, ""); +static_assert(sizeof(small_string<wchar_t>) == 6, ""); +# else +# error "Unexpected wchar_t width" +# endif +# endif + +# ifndef TEST_HAS_NO_CHAR8_T +static_assert(sizeof(std::u8string) == 24, ""); +static_assert(sizeof(min_string<char8_t>) == 24, ""); +static_assert(sizeof(test_string<char8_t>) == 32, ""); +static_assert(sizeof(small_string<char8_t>) == 6, ""); +# endif + +# ifndef TEST_HAS_NO_UNICODE_CHARS +static_assert(sizeof(std::u16string) == 24, ""); +static_assert(sizeof(std::u32string) == 24, ""); +static_assert(sizeof(min_string<char16_t>) == 24, ""); +static_assert(sizeof(min_string<char32_t>) == 24, ""); +static_assert(sizeof(test_string<char16_t>) == 32, ""); +static_assert(sizeof(test_string<char32_t>) == 32, ""); +static_assert(sizeof(small_string<char16_t>) == 6, ""); +static_assert(sizeof(small_string<char32_t>) == 12, ""); +# endif + +#elif __SIZE_WIDTH__ == 32 + +static_assert(sizeof(std::string) == 12, ""); +static_assert(sizeof(min_string<char>) == 12, ""); +static_assert(sizeof(test_string<char>) == 24, ""); +static_assert(sizeof(small_string<char>) == 6, ""); + +# ifndef TEST_HAS_NO_WIDE_CHARACTERS +# if __WCHAR_WIDTH__ == 32 +static_assert(sizeof(std::wstring) == 12, ""); +static_assert(sizeof(min_string<wchar_t>) == 12, ""); +static_assert(sizeof(test_string<wchar_t>) == 24, ""); +static_assert(sizeof(small_string<wchar_t>) == 12, ""); +# elif __WCHAR_WIDTH__ == 16 +static_assert(sizeof(std::wstring) == 12, ""); +static_assert(sizeof(min_string<wchar_t>) == 12, ""); +static_assert(sizeof(test_string<wchar_t>) == 24, ""); +static_assert(sizeof(small_string<wchar_t>) == 6, ""); +# else +# error "Unexpected wchar_t width" +# endif +# endif + +# ifndef TEST_HAS_NO_CHAR8_T +static_assert(sizeof(std::u8string) == 12, ""); +static_assert(sizeof(min_string<char8_t>) == 12, ""); +static_assert(sizeof(test_string<char8_t>) == 24, ""); +static_assert(sizeof(small_string<char>) == 6, ""); +# endif + +# ifndef TEST_HAS_NO_UNICODE_CHARS +static_assert(sizeof(std::u16string) == 12, ""); +static_assert(sizeof(std::u32string) == 12, ""); +static_assert(sizeof(min_string<char16_t>) == 12, ""); +static_assert(sizeof(min_string<char32_t>) == 12, ""); +static_assert(sizeof(test_string<char16_t>) == 24, ""); +static_assert(sizeof(test_string<char32_t>) == 24, ""); +static_assert(sizeof(small_string<char16_t>) == 6, ""); +static_assert(sizeof(small_string<char32_t>) == 12, ""); +# endif + +#else +# error "std::size_t has an unexpected size" +#endif diff --git a/libcxx/test/libcxx-03/strings/basic.string/string.capacity/allocation_size.pass.cpp b/libcxx/test/libcxx-03/strings/basic.string/string.capacity/allocation_size.pass.cpp new file mode 100644 index 000000000000..77da29225957 --- /dev/null +++ b/libcxx/test/libcxx-03/strings/basic.string/string.capacity/allocation_size.pass.cpp @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// 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> + +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <string> + +#include "test_macros.h" + +// alignment of the string heap buffer is hardcoded to 8 +const std::size_t alignment = 8; + +int main(int, char**) { + std::string input_string; + input_string.resize(64, 'a'); + + // Call a constructor which selects its size using __recommend. + std::string test_string(input_string.data()); + const std::size_t expected_align8_size = 71; + + // Demonstrate the lesser capacity/allocation size when the alignment requirement is 8. + if (alignment == 8) { + assert(test_string.capacity() == expected_align8_size); + } else { + assert(test_string.capacity() == expected_align8_size + 8); + } + + return 0; +} diff --git a/libcxx/test/libcxx-03/strings/basic.string/string.capacity/max_size.pass.cpp b/libcxx/test/libcxx-03/strings/basic.string/string.capacity/max_size.pass.cpp new file mode 100644 index 000000000000..6bfcb5d4bfcd --- /dev/null +++ b/libcxx/test/libcxx-03/strings/basic.string/string.capacity/max_size.pass.cpp @@ -0,0 +1,120 @@ +//===----------------------------------------------------------------------===// +// +// 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> + +// This test ensures that the correct max_size() is returned depending on the platform. + +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <string> + +#include "test_macros.h" + +// alignment of the string heap buffer is hardcoded to 8 +static const std::size_t alignment = 8; + +template <class = int> +TEST_CONSTEXPR_CXX20 void full_size() { + std::string str; + assert(str.max_size() == std::numeric_limits<std::size_t>::max() - alignment - 1); + +#ifndef TEST_HAS_NO_CHAR8_T + std::u8string u8str; + assert(u8str.max_size() == std::numeric_limits<std::size_t>::max() - alignment - 1); +#endif + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + std::wstring wstr; + assert(wstr.max_size() == + ((std::numeric_limits<std::size_t>::max() / sizeof(wchar_t) - alignment) & ~std::size_t(1)) - 1); +#endif + + std::u16string u16str; + std::u32string u32str; + assert(u16str.max_size() == ((std::numeric_limits<std::size_t>::max() / 2 - alignment) & ~std::size_t(1)) - 1); + assert(u32str.max_size() == ((std::numeric_limits<std::size_t>::max() / 4 - alignment) & ~std::size_t(1)) - 1); +} + +template <class = int> +TEST_CONSTEXPR_CXX20 void half_size() { + std::string str; + assert(str.max_size() == std::numeric_limits<std::size_t>::max() / 2 - alignment - 1); + +#ifndef TEST_HAS_NO_CHAR8_T + std::u8string u8str; + assert(u8str.max_size() == std::numeric_limits<std::size_t>::max() / 2 - alignment - 1); +#endif + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + std::wstring wstr; + assert(wstr.max_size() == + std::numeric_limits<std::size_t>::max() / std::max<size_t>(2ul, sizeof(wchar_t)) - alignment - 1); +#endif + + std::u16string u16str; + std::u32string u32str; + assert(u16str.max_size() == std::numeric_limits<std::size_t>::max() / 2 - alignment - 1); + assert(u32str.max_size() == std::numeric_limits<std::size_t>::max() / 4 - alignment - 1); +} + +TEST_CONSTEXPR_CXX20 bool test() { +#if _LIBCPP_ABI_VERSION == 1 + +# if defined(__x86_64__) || defined(__i386__) + full_size(); +# elif defined(__APPLE__) && defined(__aarch64__) + half_size(); +# elif defined(__arm__) || defined(__aarch64__) +# ifdef __BIG_ENDIAN__ + half_size(); +# else + full_size(); +# endif +# elif defined(__powerpc__) || defined(__powerpc64__) +# ifdef __BIG_ENDIAN__ + half_size(); +# else + full_size(); +# endif +# elif defined(__sparc64__) + half_size(); +# elif defined(__riscv) + full_size(); +# elif defined(_WIN32) + full_size(); +# else +# error "Your target system seems to be unsupported." +# endif + +#else + +# if defined(__arm__) || defined(__aarch64__) +# ifdef __BIG_ENDIAN__ + full_size(); +# else + half_size(); +# endif +# else + half_size(); +# endif + +#endif + + return true; +} + +int main(int, char**) { + test(); +#if TEST_STD_VER > 17 + static_assert(test()); +#endif + + return 0; +} diff --git a/libcxx/test/libcxx-03/strings/basic.string/string.cons/copy_shrunk_long.pass.cpp b/libcxx/test/libcxx-03/strings/basic.string/string.cons/copy_shrunk_long.pass.cpp new file mode 100644 index 000000000000..d4a0b318f36d --- /dev/null +++ b/libcxx/test/libcxx-03/strings/basic.string/string.cons/copy_shrunk_long.pass.cpp @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// +// 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> + +// basic_string(const basic_string<charT,traits,Allocator>& str); + +#include <string> +#include <cassert> + +#include "test_macros.h" +#include "test_allocator.h" +#include "min_allocator.h" + +template <class S> +TEST_CONSTEXPR_CXX20 bool test() { + // Tests that a long string holding a SSO size string results in + // an SSO copy constructed value. + S s1("1234567890123456789012345678901234567890123456789012345678901234567890"); + s1.resize(7); + S s2(s1); + LIBCPP_ASSERT(s2.__invariants()); + assert(s2 == s1); + assert(s2.capacity() < sizeof(S)); + + return true; +} + +int main(int, char**) { + test<std::basic_string<char, std::char_traits<char>, test_allocator<char> > >(); +#if TEST_STD_VER >= 11 + test<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>(); +#endif +#if TEST_STD_VER > 17 + static_assert(test<std::basic_string<char, std::char_traits<char>, test_allocator<char>>>()); + static_assert(test<std::basic_string<char, std::char_traits<char>, min_allocator<char>>>()); +#endif + + return 0; +} diff --git a/libcxx/test/libcxx-03/strings/basic.string/string.modifiers/resize_default_initialized.pass.cpp b/libcxx/test/libcxx-03/strings/basic.string/string.modifiers/resize_default_initialized.pass.cpp new file mode 100644 index 000000000000..8e6e07d659c1 --- /dev/null +++ b/libcxx/test/libcxx-03/strings/basic.string/string.modifiers/resize_default_initialized.pass.cpp @@ -0,0 +1,75 @@ +//===----------------------------------------------------------------------===// +// +// 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> + +// __resize_default_init(size_type) + +#include <string> +#include <cassert> + +#include "test_macros.h" + +TEST_CONSTEXPR_CXX20 void write_c_str(char* buf, int size) { + for (int i = 0; i < size; ++i) { + buf[i] = 'a'; + } + buf[size] = '\0'; +} + +template <class S> +TEST_CONSTEXPR_CXX20 void test_buffer_usage() { + { + unsigned buff_size = 125; + unsigned used_size = buff_size - 16; + S s; + s.__resize_default_init(buff_size); + write_c_str(&s[0], used_size); + assert(s.size() == buff_size); + assert(std::char_traits<char>().length(s.data()) == used_size); + s.__resize_default_init(used_size); + assert(s.size() == used_size); + assert(s.data()[used_size] == '\0'); + for (unsigned i = 0; i < used_size; ++i) { + assert(s[i] == 'a'); + } + } +} + +template <class S> +TEST_CONSTEXPR_CXX20 void test_basic() { + { + S s; + s.__resize_default_init(3); + assert(s.size() == 3); + assert(s.data()[3] == '\0'); + for (int i = 0; i < 3; ++i) + s[i] = 'a' + i; + s.__resize_default_init(1); + assert(s[0] == 'a'); + assert(s.data()[1] == '\0'); + assert(s.size() == 1); + } +} + +template <class S> +TEST_CONSTEXPR_CXX20 bool test() { + test_basic<S>(); + test_buffer_usage<S>(); + + return true; +} + +int main(int, char**) { + test<std::string>(); +#if TEST_STD_VER > 17 + static_assert(test<std::string>()); +#endif + + return 0; +} diff --git a/libcxx/test/libcxx-03/strings/c.strings/constexpr_memmove.pass.cpp b/libcxx/test/libcxx-03/strings/c.strings/constexpr_memmove.pass.cpp new file mode 100644 index 000000000000..d2ca5a265852 --- /dev/null +++ b/libcxx/test/libcxx-03/strings/c.strings/constexpr_memmove.pass.cpp @@ -0,0 +1,155 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// _Tp* __constexpr_memmove(_Tp* __dest, _Up* __src, __element_count __n); +// +// General tests for __constexpr_memmove. +// +// In particular, we try to ensure that __constexpr_memmove behaves like +// __builtin_memmove as closely as possible. This means that it produces the +// same effect, but also that it has the same type requirements. +// +// __builtin_memmove only requires that the types are TriviallyCopyable +// (which is interestingly different from both is_trivially_XXX_constructible +// and is_trivially_XXX_assignable), so we use some funky types to test these +// corner cases. + +#include <__cxx03/__string/constexpr_c_functions.h> +#include <cassert> +#include <cstdint> +#include <type_traits> + +#include "test_macros.h" + +// The following types are all TriviallyCopyable, but they are not all +// trivially_{copy,move}_{constructible,assignable}. TriviallyCopyable +// guarantees that the type is *at least* one of the four, but no more +// than that. +struct CopyConstructible { + CopyConstructible() = default; + int value = 0; + + CopyConstructible(const CopyConstructible&) = default; + CopyConstructible(CopyConstructible&&) = delete; + CopyConstructible& operator=(const CopyConstructible&) = delete; + CopyConstructible& operator=(CopyConstructible&&) = delete; +}; + +struct MoveConstructible { + MoveConstructible() = default; + int value = 0; + + MoveConstructible(const MoveConstructible&) = delete; + MoveConstructible(MoveConstructible&&) = default; + MoveConstructible& operator=(const MoveConstructible&) = delete; + MoveConstructible& operator=(MoveConstructible&&) = delete; +}; + +struct CopyAssignable { + CopyAssignable() = default; + int value = 0; + + CopyAssignable(const CopyAssignable&) = delete; + CopyAssignable(CopyAssignable&&) = delete; + CopyAssignable& operator=(const CopyAssignable&) = default; + CopyAssignable& operator=(CopyAssignable&&) = delete; +}; + +struct MoveAssignable { + MoveAssignable() = default; + int value = 0; + + MoveAssignable(const MoveAssignable&) = delete; + MoveAssignable(MoveAssignable&&) = delete; + MoveAssignable& operator=(const MoveAssignable&) = delete; + MoveAssignable& operator=(MoveAssignable&&) = default; +}; + +template <class Source, class Dest> +TEST_CONSTEXPR_CXX14 void test_user_defined_types() { + static_assert(std::is_trivially_copyable<Source>::value, "test the test"); + static_assert(std::is_trivially_copyable<Dest>::value, "test the test"); + + // Note that we can't just initialize with an initializer list since some of the types we use here + // are not copy-constructible, which is required in pre-C++20 Standards for that syntax to work. + Source src[3]; + src[0].value = 1; + src[1].value = 2; + src[2].value = 3; + Dest dst[3]; + dst[0].value = 111; + dst[1].value = 111; + dst[2].value = 111; + + Dest* result = std::__constexpr_memmove(dst, src, std::__element_count(3)); + assert(result == dst); + assert(dst[0].value == 1); + assert(dst[1].value == 2); + assert(dst[2].value == 3); +} + +template <class Source, class Dest> +TEST_CONSTEXPR_CXX14 void test_builtin_types() { + Source src[3] = {1, 2, 3}; + Dest dst[3] = {111, 111, 111}; + + Dest* result = std::__constexpr_memmove(dst, src, std::__element_count(3)); + assert(result == dst); + assert(dst[0] == 1); + assert(dst[1] == 2); + assert(dst[2] == 3); +} + +template <class SourcePtr, class DestPtr, class ObjectType> +TEST_CONSTEXPR_CXX14 void test_pointer_types() { + ObjectType objs[3] = {1, 2, 3}; + + SourcePtr src[3] = {objs + 0, objs + 1, objs + 2}; + DestPtr dst[3] = {nullptr, nullptr, nullptr}; + + DestPtr* result = std::__constexpr_memmove(dst, src, std::__element_count(3)); + assert(result == dst); + assert(dst[0] == objs + 0); + assert(dst[1] == objs + 1); + assert(dst[2] == objs + 2); +} + +TEST_CONSTEXPR_CXX14 bool test() { + test_user_defined_types<CopyConstructible, CopyConstructible>(); + test_user_defined_types<MoveConstructible, MoveConstructible>(); + test_user_defined_types<CopyAssignable, CopyAssignable>(); + test_user_defined_types<MoveAssignable, MoveAssignable>(); + + test_builtin_types<char, char>(); + test_builtin_types<short, short>(); + test_builtin_types<int, int>(); + test_builtin_types<long, long>(); + test_builtin_types<long long, long long>(); + + // Cross-type + test_builtin_types<std::int16_t, std::uint16_t>(); + test_builtin_types<std::int16_t, char16_t>(); + test_builtin_types<std::int32_t, std::uint32_t>(); + test_builtin_types<std::int32_t, char32_t>(); + + test_pointer_types<char*, char*, char>(); + test_pointer_types<int*, int*, int>(); + test_pointer_types<long*, long*, long>(); + test_pointer_types<void*, void*, int>(); + test_pointer_types<int* const, int*, int>(); + + return true; +} + +int main(int, char**) { + test(); +#if TEST_STD_VER >= 14 + static_assert(test(), ""); +#endif + return 0; +} diff --git a/libcxx/test/libcxx-03/strings/string.view/string.view.iterators/assert.iterator-indexing.pass.cpp b/libcxx/test/libcxx-03/strings/string.view/string.view.iterators/assert.iterator-indexing.pass.cpp new file mode 100644 index 000000000000..5043a88cbc3d --- /dev/null +++ b/libcxx/test/libcxx-03/strings/string.view/string.view.iterators/assert.iterator-indexing.pass.cpp @@ -0,0 +1,158 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// Make sure that std::string_view's iterators check for OOB accesses when the debug mode is enabled. + +// REQUIRES: has-unix-headers, libcpp-has-abi-bounded-iterators +// UNSUPPORTED: libcpp-hardening-mode=none + +#include <iterator> +#include <string_view> + +#include "check_assertion.h" + +template <typename Iter> +void test_iterator(Iter begin, Iter end, bool reverse) { + ptrdiff_t distance = std::distance(begin, end); + + // Dereferencing an iterator at the end. + { + TEST_LIBCPP_ASSERT_FAILURE( + *end, + reverse ? "__bounded_iter::operator--: Attempt to rewind an iterator past the start" + : "__bounded_iter::operator*: Attempt to dereference an iterator at the end"); +#if _LIBCPP_STD_VER >= 20 + // In C++20 mode, std::reverse_iterator implements operator->, but not operator*, with + // std::prev instead of operator--. std::prev ultimately calls operator+ + TEST_LIBCPP_ASSERT_FAILURE( + end.operator->(), + reverse ? "__bounded_iter::operator+=: Attempt to rewind an iterator past the start" + : "__bounded_iter::operator->: Attempt to dereference an iterator at the end"); +#else + TEST_LIBCPP_ASSERT_FAILURE( + end.operator->(), + reverse ? "__bounded_iter::operator--: Attempt to rewind an iterator past the start" + : "__bounded_iter::operator->: Attempt to dereference an iterator at the end"); +#endif + } + + // Incrementing an iterator past the end. + { + [[maybe_unused]] const char* msg = + reverse ? "__bounded_iter::operator--: Attempt to rewind an iterator past the start" + : "__bounded_iter::operator++: Attempt to advance an iterator past the end"; + auto it = end; + TEST_LIBCPP_ASSERT_FAILURE(it++, msg); + it = end; + TEST_LIBCPP_ASSERT_FAILURE(++it, msg); + } + + // Decrementing an iterator past the start. + { + [[maybe_unused]] const char* msg = + reverse ? "__bounded_iter::operator++: Attempt to advance an iterator past the end" + : "__bounded_iter::operator--: Attempt to rewind an iterator past the start"; + auto it = begin; + TEST_LIBCPP_ASSERT_FAILURE(it--, msg); + it = begin; + TEST_LIBCPP_ASSERT_FAILURE(--it, msg); + } + + // Advancing past the end with operator+= and operator+. + { + [[maybe_unused]] const char* msg = + reverse ? "__bounded_iter::operator-=: Attempt to rewind an iterator past the start" + : "__bounded_iter::operator+=: Attempt to advance an iterator past the end"; + auto it = end; + TEST_LIBCPP_ASSERT_FAILURE(it += 1, msg); + TEST_LIBCPP_ASSERT_FAILURE(end + 1, msg); + it = begin; + TEST_LIBCPP_ASSERT_FAILURE(it += (distance + 1), msg); + TEST_LIBCPP_ASSERT_FAILURE(begin + (distance + 1), msg); + } + + // Advancing past the end with operator-= and operator-. + { + [[maybe_unused]] const char* msg = + reverse ? "__bounded_iter::operator+=: Attempt to rewind an iterator past the start" + : "__bounded_iter::operator-=: Attempt to advance an iterator past the end"; + auto it = end; + TEST_LIBCPP_ASSERT_FAILURE(it -= (-1), msg); + TEST_LIBCPP_ASSERT_FAILURE(end - (-1), msg); + it = begin; + TEST_LIBCPP_ASSERT_FAILURE(it -= (-distance - 1), msg); + TEST_LIBCPP_ASSERT_FAILURE(begin - (-distance - 1), msg); + } + + // Rewinding past the start with operator+= and operator+. + { + [[maybe_unused]] const char* msg = + reverse ? "__bounded_iter::operator-=: Attempt to advance an iterator past the end" + : "__bounded_iter::operator+=: Attempt to rewind an iterator past the start"; + auto it = begin; + TEST_LIBCPP_ASSERT_FAILURE(it += (-1), msg); + TEST_LIBCPP_ASSERT_FAILURE(begin + (-1), msg); + it = end; + TEST_LIBCPP_ASSERT_FAILURE(it += (-distance - 1), msg); + TEST_LIBCPP_ASSERT_FAILURE(end + (-distance - 1), msg); + } + + // Rewinding past the start with operator-= and operator-. + { + [[maybe_unused]] const char* msg = + reverse ? "__bounded_iter::operator+=: Attempt to advance an iterator past the end" + : "__bounded_iter::operator-=: Attempt to rewind an iterator past the start"; + auto it = begin; + TEST_LIBCPP_ASSERT_FAILURE(it -= 1, msg); + TEST_LIBCPP_ASSERT_FAILURE(begin - 1, msg); + it = end; + TEST_LIBCPP_ASSERT_FAILURE(it -= (distance + 1), msg); + TEST_LIBCPP_ASSERT_FAILURE(end - (distance + 1), msg); + } + + // Out-of-bounds operator[]. + { + [[maybe_unused]] const char* end_msg = + reverse ? "__bounded_iter::operator--: Attempt to rewind an iterator past the start" + : "__bounded_iter::operator[]: Attempt to index an iterator at or past the end"; + [[maybe_unused]] const char* past_end_msg = + reverse ? "__bounded_iter::operator-=: Attempt to rewind an iterator past the start" + : "__bounded_iter::operator[]: Attempt to index an iterator at or past the end"; + [[maybe_unused]] const char* past_start_msg = + reverse ? "__bounded_iter::operator-=: Attempt to advance an iterator past the end" + : "__bounded_iter::operator[]: Attempt to index an iterator past the start"; + TEST_LIBCPP_ASSERT_FAILURE(begin[distance], end_msg); + TEST_LIBCPP_ASSERT_FAILURE(begin[distance + 1], past_end_msg); + TEST_LIBCPP_ASSERT_FAILURE(begin[-1], past_start_msg); + TEST_LIBCPP_ASSERT_FAILURE(begin[-99], past_start_msg); + + auto it = begin + 1; + TEST_LIBCPP_ASSERT_FAILURE(it[distance - 1], end_msg); + TEST_LIBCPP_ASSERT_FAILURE(it[distance], past_end_msg); + TEST_LIBCPP_ASSERT_FAILURE(it[-2], past_start_msg); + TEST_LIBCPP_ASSERT_FAILURE(it[-99], past_start_msg); + } +} + +int main(int, char**) { + std::string_view const str("hello world"); + + // string_view::iterator + test_iterator(str.begin(), str.end(), /*reverse=*/false); + + // string_view::const_iterator + test_iterator(str.cbegin(), str.cend(), /*reverse=*/false); + + // string_view::reverse_iterator + test_iterator(str.rbegin(), str.rend(), /*reverse=*/true); + + // string_view::const_reverse_iterator + test_iterator(str.crbegin(), str.crend(), /*reverse=*/true); + + return 0; +} |
