|
| 1 | +//===----------------------------------------------------------------------===// |
| 2 | +// |
| 3 | +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | +// See https://llvm.org/LICENSE.txt for license information. |
| 5 | +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | +// |
| 7 | +//===----------------------------------------------------------------------===// |
| 8 | + |
| 9 | +// <string> |
| 10 | + |
| 11 | +// XFAIL: FROZEN-CXX03-HEADERS-FIXME |
| 12 | + |
| 13 | +// Make sure basic_string constructors and functions operate properly for allocators with small `size_type`s. |
| 14 | +// Related issue: https://github.com/llvm/llvm-project/issues/125187 |
| 15 | + |
| 16 | +// constexpr basic_string( |
| 17 | +// basic_string&& str, size_type pos, size_type n, const Allocator& a = Allocator()); // C++23 |
| 18 | +// basic_string(const basic_string& str, size_type pos, size_type n, |
| 19 | +// const Allocator& a = Allocator()); // constexpr since C++20 |
| 20 | +// basic_string& assign(const basic_string& str, size_type pos, size_type n=npos); // constexpr since C++20 |
| 21 | +// template <class T> |
| 22 | +// basic_string& assign(const T& t, size_type pos, size_type n=npos); // C++17, constexpr since C++20 |
| 23 | +// basic_string& append(const basic_string& str, size_type pos, size_type n=npos); // constexpr since C++20 |
| 24 | +// template <class T> |
| 25 | +// basic_string& append(const T& t, size_type pos, size_type n=npos); // C++17, constexpr since C++20 |
| 26 | +// basic_string& insert(size_type pos1, const basic_string& str, |
| 27 | +// size_type pos2, size_type n=npos); // constexpr since C++20 |
| 28 | +// template <class T> |
| 29 | +// basic_string& insert(size_type pos1, const T& t, size_type pos2, size_type n=npos); // C++17, constexpr since C++20 |
| 30 | +// basic_string& erase(size_type pos = 0, size_type n = npos); // constexpr since C++20 |
| 31 | +// basic_string& replace(size_type pos, size_type n1, const value_type* s, size_type n2); // constexpr since C++20 |
| 32 | +// basic_string& replace(size_type pos, size_type n1, size_type n2, value_type c); // constexpr since C++20 |
| 33 | +// basic_string& replace(size_type pos1, size_type n1, const basic_string& str, |
| 34 | +// size_type pos2, size_type n2=npos); // constexpr since C++20 |
| 35 | +// template <class T> |
| 36 | +// basic_string& replace(size_type pos1, size_type n1, const T& t, |
| 37 | +// size_type pos2, size_type n2= npos); // C++17, constexpr since C++20 |
| 38 | +// size_type copy(value_type* s, size_type n, size_type pos = 0) const; // constexpr since C++20 |
| 39 | +// template <class T> |
| 40 | +// int compare(const T& t) const noexcept; // C++17, constexpr since C++20 |
| 41 | +// int compare(size_type pos1, size_type n1, const value_type* s, size_type n2) const; // constexpr since C++20 |
| 42 | + |
| 43 | +#include <cassert> |
| 44 | +#include <cstdint> |
| 45 | +#include <string> |
| 46 | +#include <string_view> |
| 47 | + |
| 48 | +#include "sized_allocator.h" |
| 49 | +#include "test_macros.h" |
| 50 | + |
| 51 | +template <class SizeT, class DiffT, class CharT = char, class Traits = std::char_traits<CharT> > |
| 52 | +TEST_CONSTEXPR_CXX20 void test_with_custom_size_type() { |
| 53 | + using Alloc = sized_allocator<CharT, SizeT, DiffT>; |
| 54 | + using string = std::basic_string<CharT, Traits, Alloc>; |
| 55 | + string s = "hello world"; |
| 56 | + |
| 57 | + // The following tests validate all possible calls to std::min within <basic_string> |
| 58 | + { // basic_string(const basic_string& str, size_type pos, size_type n, const Allocator& a = Allocator()) |
| 59 | + assert(string(s, 0, 5) == "hello"); |
| 60 | + assert(string(s, 0, 5, Alloc(3)) == "hello"); |
| 61 | + assert(string(s, 6, 5) == "world"); |
| 62 | + assert(string(s, 6, 5, Alloc(3)) == "world"); |
| 63 | + assert(string(s, 6, 100) == "world"); |
| 64 | + assert(string(s, 6, 100, Alloc(3)) == "world"); |
| 65 | + } |
| 66 | +#if TEST_STD_VER >= 23 |
| 67 | + { // constexpr basic_string(basic_string&& str, size_type pos, size_type n, const Allocator& a = Allocator()); |
| 68 | + assert(string(string(s), 0, 5) == "hello"); |
| 69 | + assert(string(string(s), 0, 5, Alloc(3)) == "hello"); |
| 70 | + assert(string(string(s), 6, 5) == "world"); |
| 71 | + assert(string(string(s), 6, 5, Alloc(3)) == "world"); |
| 72 | + assert(string(string(s), 6, 100) == "world"); |
| 73 | + assert(string(string(s), 6, 100, Alloc(3)) == "world"); |
| 74 | + } |
| 75 | +#endif |
| 76 | + { // basic_string& assign(const basic_string& str, size_type pos, size_type n=npos) |
| 77 | + string s1 = s; |
| 78 | + string s2 = "cplusplus"; |
| 79 | + s1.assign(s2, 0, 5); |
| 80 | + assert(s1 == "cplus"); |
| 81 | + s1.assign(s2, 0, 9); |
| 82 | + assert(s1 == "cplusplus"); |
| 83 | + s1.assign(s2, 5); |
| 84 | + assert(s1 == "plus"); |
| 85 | + s1.assign(s2, 0, 100); |
| 86 | + assert(s1 == "cplusplus"); |
| 87 | + s1.assign(s2, 4); |
| 88 | + assert(s1 == "splus"); |
| 89 | + s1.assign(s2, 0); |
| 90 | + assert(s1 == "cplusplus"); |
| 91 | + } |
| 92 | +#if TEST_STD_VER >= 17 |
| 93 | + { // template <class T> basic_string& assign(const T& t, size_type pos, size_type n=npos) |
| 94 | + std::string_view sv = "cplusplus"; |
| 95 | + string s1 = s; |
| 96 | + s1.assign(sv, 0, 5); |
| 97 | + assert(s1 == "cplus"); |
| 98 | + s1.assign(sv, 0, 9); |
| 99 | + assert(s1 == "cplusplus"); |
| 100 | + s1.assign(sv, 5); |
| 101 | + assert(s1 == "plus"); |
| 102 | + s1.assign(sv, 0, 100); |
| 103 | + assert(s1 == "cplusplus"); |
| 104 | + s1.assign(sv, 4); |
| 105 | + assert(s1 == "splus"); |
| 106 | + s1.assign(sv, 0); |
| 107 | + assert(s1 == "cplusplus"); |
| 108 | + } |
| 109 | +#endif |
| 110 | + { // basic_string& append(const basic_string& str, size_type pos, size_type n=npos) |
| 111 | + string s1 = s; |
| 112 | + string s2 = " of cplusplus"; |
| 113 | + s1.append(s2, 0, 5); |
| 114 | + assert(s1 == "hello world of c"); |
| 115 | + s1 = s; |
| 116 | + s1.append(s2, 0, 100); |
| 117 | + assert(s1 == "hello world of cplusplus"); |
| 118 | + s1 = s; |
| 119 | + s1.append(s2, 0); |
| 120 | + assert(s1 == "hello world of cplusplus"); |
| 121 | + } |
| 122 | +#if TEST_STD_VER >= 17 |
| 123 | + { // template <class T> basic_string& append(const T& t, size_type pos, size_type n=npos) |
| 124 | + string s1 = s; |
| 125 | + std::string_view sv = " of cplusplus"; |
| 126 | + s1.append(sv, 0, 5); |
| 127 | + assert(s1 == "hello world of c"); |
| 128 | + s1 = s; |
| 129 | + s1.append(sv, 0, 100); |
| 130 | + assert(s1 == "hello world of cplusplus"); |
| 131 | + s1 = s; |
| 132 | + s1.append(sv, 0); |
| 133 | + assert(s1 == "hello world of cplusplus"); |
| 134 | + } |
| 135 | +#endif |
| 136 | + { // basic_string& insert(size_type pos1, const basic_string& str, size_type pos2, size_type n=npos) |
| 137 | + string s1 = s; |
| 138 | + string s2 = " cplusplus"; |
| 139 | + s1.insert(5, s2, 0, 2); |
| 140 | + assert(s1 == "hello c world"); |
| 141 | + s1 = s; |
| 142 | + s1.insert(5, s2, 0, 100); |
| 143 | + assert(s1 == "hello cplusplus world"); |
| 144 | + s1 = s; |
| 145 | + s1.insert(5, s2, 0); |
| 146 | + assert(s1 == "hello cplusplus world"); |
| 147 | + } |
| 148 | +#if TEST_STD_VER >= 17 |
| 149 | + { // template <class T> basic_string& insert(size_type pos1, const T& t, size_type pos2, size_type n=npos) |
| 150 | + string s1 = s; |
| 151 | + std::string_view sv = " cplusplus"; |
| 152 | + s1.insert(5, sv, 0, 2); |
| 153 | + assert(s1 == "hello c world"); |
| 154 | + s1 = s; |
| 155 | + s1.insert(5, sv, 0, 100); |
| 156 | + assert(s1 == "hello cplusplus world"); |
| 157 | + s1 = s; |
| 158 | + s1.insert(5, sv, 0); |
| 159 | + assert(s1 == "hello cplusplus world"); |
| 160 | + } |
| 161 | +#endif |
| 162 | + { // basic_string& erase(size_type pos = 0, size_type n = npos) |
| 163 | + string s1 = s; |
| 164 | + assert(s1.erase(5, 100) == "hello"); |
| 165 | + s1 = s; |
| 166 | + assert(s1.erase(5) == "hello"); |
| 167 | + assert(s1.erase().empty()); |
| 168 | + } |
| 169 | + { // basic_string& replace(size_type pos, size_type n1, const value_type* s, size_type n2) |
| 170 | + string s1 = s; |
| 171 | + const char* s2 = "cpluscplus"; |
| 172 | + assert(s1.replace(6, 5, s2, 1) == "hello c"); |
| 173 | + assert(s1.replace(6, 1, s2, 10) == "hello cpluscplus"); |
| 174 | + } |
| 175 | + { // basic_string& replace(size_type pos, size_type n1, size_type n2, value_type c) |
| 176 | + string s1 = s; |
| 177 | + assert(s1.replace(5, 6, 2, 'o') == "hellooo"); |
| 178 | + assert(s1.replace(5, 2, 0, 'o') == "hello"); |
| 179 | + } |
| 180 | + { // basic_string& replace(size_type pos1, size_type n1, const basic_string& str, size_type pos2, size_type n2=npos) |
| 181 | + string s1 = s; |
| 182 | + string s2 = "cplusplus"; |
| 183 | + assert(s1.replace(6, 5, s2, 0, 1) == "hello c"); |
| 184 | + assert(s1.replace(7, 0, s2, 1, 9) == "hello cplusplus"); |
| 185 | + s1 = s; |
| 186 | + assert(s1.replace(6, 5, s2, 0, 100) == "hello cplusplus"); |
| 187 | + s1 = s; |
| 188 | + assert(s1.replace(6, 5, s2, 0) == "hello cplusplus"); |
| 189 | + } |
| 190 | +#if TEST_STD_VER >= 17 |
| 191 | + { // template <class T> basic_string& replace(size_type pos1, size_type n1, const T& t, size_type pos2, size_type n2= npos) |
| 192 | + string s1 = s; |
| 193 | + std::string_view sv = "cplusplus"; |
| 194 | + assert(s1.replace(6, 5, sv, 0, 1) == "hello c"); |
| 195 | + assert(s1.replace(7, 0, sv, 1, 9) == "hello cplusplus"); |
| 196 | + s1 = s; |
| 197 | + assert(s1.replace(6, 5, sv, 0, 100) == "hello cplusplus"); |
| 198 | + s1 = s; |
| 199 | + assert(s1.replace(6, 5, sv, 0) == "hello cplusplus"); |
| 200 | + } |
| 201 | +#endif |
| 202 | + { // size_type copy(value_type* s, size_type n, size_type pos = 0) const |
| 203 | + string s1 = s; |
| 204 | + char bar[100] = {}; |
| 205 | + s1.copy(bar, s1.size()); |
| 206 | + assert(s1 == bar); |
| 207 | + } |
| 208 | + { // int compare(size_type pos1, size_type n1, const value_type* s, size_type n2) const |
| 209 | + string s1 = s; |
| 210 | + assert(s1.compare(0, 11, "hello world", 11) == 0); |
| 211 | + assert(s1.compare(0, 11, "hello", 11) > 0); |
| 212 | + assert(s1.compare(0, 11, "hello world C++", 100) < 0); |
| 213 | + } |
| 214 | +#if TEST_STD_VER >= 17 |
| 215 | + { // template <class T> int compare(const T& t) const noexcept; |
| 216 | + using std::operator""sv; |
| 217 | + string s1 = s; |
| 218 | + assert(s1.compare("hello world"sv) == 0); |
| 219 | + assert(s1.compare("hello"sv) > 0); |
| 220 | + assert(s1.compare("hello world C++"sv) < 0); |
| 221 | + } |
| 222 | +#endif |
| 223 | +} |
| 224 | + |
| 225 | +TEST_CONSTEXPR_CXX20 bool test() { |
| 226 | + test_with_custom_size_type<std::uint8_t, std::int8_t>(); |
| 227 | + test_with_custom_size_type<std::uint16_t, std::int16_t>(); |
| 228 | + test_with_custom_size_type<std::uint32_t, std::int32_t>(); |
| 229 | + test_with_custom_size_type<std::uint64_t, std::int64_t>(); |
| 230 | + test_with_custom_size_type<std::size_t, std::ptrdiff_t>(); |
| 231 | + test_with_custom_size_type<unsigned char, int>(); |
| 232 | + test_with_custom_size_type<unsigned short, short>(); |
| 233 | + test_with_custom_size_type<unsigned, int>(); |
| 234 | + |
| 235 | + return true; |
| 236 | +} |
| 237 | + |
| 238 | +int main(int, char**) { |
| 239 | + test(); |
| 240 | +#if TEST_STD_VER > 17 |
| 241 | + static_assert(test()); |
| 242 | +#endif |
| 243 | + |
| 244 | + return 0; |
| 245 | +} |
0 commit comments