diff --git a/c10/macros/Macros.h b/c10/macros/Macros.h index c5025ad824f..2b75f09f677 100644 --- a/c10/macros/Macros.h +++ b/c10/macros/Macros.h @@ -263,4 +263,13 @@ constexpr uint32_t CUDA_THREADS_PER_BLOCK_FALLBACK = 256; #define C10_CPP14_HOST_CONSTEXPR AT_CPP14_CONSTEXPR #endif +#if !defined(__clang__) && !defined(_MSC_VER) && defined(__GNUC__) && \ + __GNUC__ < 6 +#define CONSTEXPR_EXCEPT_GCC5 +#define IS_NOT_GCC5_CONSTEXPR 0 +#else +#define CONSTEXPR_EXCEPT_GCC5 AT_CPP14_CONSTEXPR +#define IS_NOT_GCC5_CONSTEXPR AT_IS_CPP14_CONSTEXPR +#endif + #endif // C10_MACROS_MACROS_H_ diff --git a/c10/test/util/C++17_test.cpp b/c10/test/util/C++17_test.cpp new file mode 100644 index 00000000000..ad8e45e2acf --- /dev/null +++ b/c10/test/util/C++17_test.cpp @@ -0,0 +1,14 @@ +#include + +using c10::guts::max; +using c10::guts::min; + +static_assert(min(3, 5) == 3, ""); +static_assert(min(5, 3) == 3, ""); +static_assert(min(3, 3) == 3, ""); +static_assert(min(3.0, 3.1) == 3.0, ""); + +static_assert(max(3, 5) == 5, ""); +static_assert(max(5, 3) == 5, ""); +static_assert(max(3, 3) == 3, ""); +static_assert(max(3.0, 3.1) == 3.1, ""); diff --git a/c10/test/util/string_view_test.cpp b/c10/test/util/string_view_test.cpp new file mode 100644 index 00000000000..9c243e04898 --- /dev/null +++ b/c10/test/util/string_view_test.cpp @@ -0,0 +1,1685 @@ +#include + +#include + +using c10::string_view; + +namespace { +namespace testutils { +constexpr bool string_equal(const char* lhs, const char* rhs, size_t size) { + return (size == 0) + ? true + : (*lhs != *rhs) ? false : string_equal(lhs + 1, rhs + 1, size - 1); +} +static_assert(string_equal("hi", "hi", 2), ""); +static_assert(string_equal("", "", 0), ""); +static_assert(string_equal("hi", "hi2", 2), ""); +static_assert(string_equal("hi2", "hi", 2), ""); +static_assert(!string_equal("hi", "hi2", 3), ""); +static_assert(!string_equal("hi2", "hi", 3), ""); +static_assert(!string_equal("hi", "ha", 2), ""); + +template +inline void expectThrows(Functor&& functor, const char* expectMessageContains) { + try { + std::forward(functor)(); + } catch (const Exception& e) { + EXPECT_THAT(e.what(), testing::HasSubstr(expectMessageContains)); + return; + } + ADD_FAILURE() << "Expected to throw exception containing \"" + << expectMessageContains << "\" but didn't throw"; +} +} // namespace testutils + +using testutils::expectThrows; +using testutils::string_equal; + +namespace test_typedefs { +static_assert(std::is_same::value, ""); +static_assert(std::is_same::value, ""); +static_assert(std::is_same::value, ""); +static_assert(std::is_same::value, ""); +static_assert( + std::is_same::value, + ""); +static_assert(std::is_same::value, ""); +static_assert( + std::is_same::value, + ""); +} // namespace test_typedefs + +namespace test_default_constructor { +static_assert(string_view().size() == 0, ""); +static_assert(string_view().data() == nullptr, ""); +static_assert(string_view() == string_view(""), ""); +} // namespace test_default_constructor + +namespace test_constchar_constructor { +static_assert(string_view("").size() == 0, ""); +constexpr string_view hello = "hello"; +static_assert(5 == hello.size(), ""); +static_assert(string_equal("hello", hello.data(), hello.size()), ""); +} // namespace test_constchar_constructor + +namespace test_sized_constructor { +static_assert(string_view("", 0).size() == 0, ""); +constexpr string_view hell("hello", 4); +static_assert(4 == hell.size(), ""); +static_assert(string_equal("hell", hell.data(), hell.size()), ""); +} // namespace test_sized_constructor + +namespace test_string_constructor { +void test_conversion_is_implicit(string_view a) {} +TEST(StringViewTest, testStringConstructor) { + std::string empty; + EXPECT_EQ(0, string_view(empty).size()); + std::string hello_str = "hello"; + string_view hello_sv = hello_str; + EXPECT_EQ(5, hello_sv.size()); + EXPECT_TRUE(string_equal("hello", hello_sv.data(), hello_sv.size())); + + test_conversion_is_implicit(hello_str); +} +} // namespace test_string_constructor + +namespace test_conversion_to_string { +TEST(StringViewTest, testConversionToString) { + string_view empty; + EXPECT_EQ(0, std::string(empty).size()); + string_view hello_sv = "hello"; + std::string hello_str(hello_sv); + EXPECT_EQ(5, hello_str.size()); + EXPECT_EQ(std::string("hello"), hello_str); +} +} // namespace test_conversion_to_string + +namespace test_copy_constructor { +constexpr string_view hello = "hello"; +constexpr string_view copy = hello; +static_assert(5 == copy.size(), ""); +static_assert(string_equal("hello", copy.data(), copy.size()), ""); +} // namespace test_copy_constructor + +namespace test_copy_assignment { +AT_CPP14_CONSTEXPR string_view assign(string_view value) { + string_view result = "temporary_content"; + result = value; // this is the assignment we're testing + return result; +} +TEST(StringViewTest, testCopyAssignment) { +#if defined(__cpp_constexpr) && __cpp_constexpr >= 201304 + { + constexpr string_view hello = assign("hello"); + static_assert(5 == hello.size(), ""); + static_assert(string_equal("hello", hello.data(), hello.size()), ""); + + static_assert(5 == (string_view() = "hello").size(), ""); + static_assert( + string_equal("hello", (string_view() = "hello").data(), 5), ""); + } +#endif + const string_view hello = assign("hello"); + EXPECT_EQ(5, hello.size()); + EXPECT_EQ("hello", hello); + EXPECT_EQ(5, (string_view() = "hello").size()); + EXPECT_EQ("hello", (string_view() = "hello")); +} + +} // namespace test_copy_assignment + +namespace test_iterators { +static_assert('h' == *string_view("hello").begin(), ""); +static_assert('h' == *string_view("hello").cbegin(), ""); +static_assert('h' == *begin(string_view("hello")), ""); +static_assert('o' == *(string_view("hello").end() - 1), ""); +static_assert('o' == *(string_view("hello").cend() - 1), ""); +static_assert('o' == *(end(string_view("hello")) - 1), ""); +static_assert('o' == *string_view("hello").rbegin(), ""); +static_assert('o' == *string_view("hello").crbegin(), ""); +static_assert('h' == *(string_view("hello").rend() - 1), ""); +static_assert('h' == *(string_view("hello").crend() - 1), ""); +} // namespace test_iterators + +namespace test_forward_iteration { +constexpr string_view hello = "hello"; +static_assert('h' == *(hello.begin() + 0), ""); +static_assert('e' == *(hello.begin() + 1), ""); +static_assert('l' == *(hello.begin() + 2), ""); +static_assert('l' == *(hello.begin() + 3), ""); +static_assert('o' == *(hello.begin() + 4), ""); +static_assert(hello.end() == hello.begin() + 5, ""); +} // namespace test_forward_iteration + +namespace test_reverse_iteration { +constexpr string_view hello = "hello"; +static_assert('o' == *(hello.rbegin() + 0), ""); +static_assert('l' == *(hello.rbegin() + 1), ""); +static_assert('l' == *(hello.rbegin() + 2), ""); +static_assert('e' == *(hello.rbegin() + 3), ""); +static_assert('h' == *(hello.rbegin() + 4), ""); +static_assert(hello.rend() == hello.rbegin() + 5, ""); +} // namespace test_reverse_iteration + +namespace test_random_access { +constexpr string_view hello = "hello"; +static_assert('h' == hello[0], ""); +static_assert('e' == hello[1], ""); +static_assert('l' == hello[2], ""); +static_assert('l' == hello[3], ""); +static_assert('o' == hello[4], ""); + +static_assert('h' == hello.at(0), ""); +static_assert('e' == hello.at(1), ""); +static_assert('l' == hello.at(2), ""); +static_assert('l' == hello.at(3), ""); +static_assert('o' == hello.at(4), ""); + +TEST(StringViewTest, whenCallingAccessOperatorOutOfRange_thenThrows) { + expectThrows( + [] { string_view("")[1]; }, + "string_view::operator[] or string_view::at() out of range. Index: 1, size: 0"); + + expectThrows( + [] { string_view("").at(1); }, + "string_view::operator[] or string_view::at() out of range. Index: 1, size: 0"); + + expectThrows( + [] { string_view("hello")[5]; }, + "string_view::operator[] or string_view::at() out of range. Index: 5, size: 5"); + + expectThrows( + [] { string_view("hello").at(5); }, + "string_view::operator[] or string_view::at() out of range. Index: 5, size: 5"); + + expectThrows( + [] { string_view("hello")[100]; }, + "string_view::operator[] or string_view::at() out of range. Index: 100, size: 5"); + + expectThrows( + [] { string_view("hello").at(100); }, + "string_view::operator[] or string_view::at() out of range. Index: 100, size: 5"); + + expectThrows( + [] { string_view("hello")[string_view::npos]; }, + "string_view::operator[] or string_view::at() out of range. Index: 18446744073709551615, size: 5"); + + expectThrows( + [] { string_view("hello").at(string_view::npos); }, + "string_view::operator[] or string_view::at() out of range. Index: 18446744073709551615, size: 5"); +} +} // namespace test_random_access + +namespace test_front_back { +static_assert('h' == string_view("hello").front(), ""); +static_assert('o' == string_view("hello").back(), ""); +} // namespace test_front_back + +namespace test_data { +static_assert(string_equal("hello", string_view("hello").data(), 5), ""); +} + +namespace test_size_length { +static_assert(0 == string_view("").size(), ""); +static_assert(5 == string_view("hello").size(), ""); + +static_assert(0 == string_view("").length(), ""); +static_assert(5 == string_view("hello").length(), ""); +} // namespace test_size_length + +namespace test_empty { +static_assert(string_view().empty(), ""); +static_assert(string_view("").empty(), ""); +static_assert(!string_view("hello").empty(), ""); +} // namespace test_empty + +namespace test_remove_prefix { +CONSTEXPR_EXCEPT_GCC5 string_view remove_prefix(string_view input, size_t len) { + input.remove_prefix(len); + return input; +} + +TEST(StringViewTest, whenRemovingValidPrefix_thenWorks) { +#if IS_NOT_GCC5_CONSTEXPR + static_assert( + remove_prefix(string_view("hello"), 0) == string_view("hello"), ""); + static_assert( + remove_prefix(string_view("hello"), 1) == string_view("ello"), ""); + static_assert(remove_prefix(string_view("hello"), 5) == string_view(""), ""); +#endif + + EXPECT_EQ(remove_prefix(string_view("hello"), 0), string_view("hello")); + EXPECT_EQ(remove_prefix(string_view("hello"), 1), string_view("ello")); + EXPECT_EQ(remove_prefix(string_view("hello"), 5), string_view("")); +} + +TEST(StringViewTest, whenRemovingTooLargePrefix_thenThrows) { + expectThrows( + [] { remove_prefix(string_view("hello"), 6); }, + "basic_string_view::remove_prefix: out of range. PrefixLength: 6, size: 5"); +} +} // namespace test_remove_prefix + +namespace test_remove_suffix { +CONSTEXPR_EXCEPT_GCC5 string_view remove_suffix(string_view input, size_t len) { + input.remove_suffix(len); + return input; +} + +TEST(StringViewTest, whenRemovingValidSuffix_thenWorks) { +#if IS_NOT_GCC5_CONSTEXPR + static_assert( + remove_suffix(string_view("hello"), 0) == string_view("hello"), ""); + static_assert( + remove_suffix(string_view("hello"), 1) == string_view("hell"), ""); + static_assert(remove_suffix(string_view("hello"), 5) == string_view(""), ""); +#endif + + EXPECT_EQ(remove_suffix(string_view("hello"), 0), string_view("hello")); + EXPECT_EQ(remove_suffix(string_view("hello"), 1), string_view("hell")); + EXPECT_EQ(remove_suffix(string_view("hello"), 5), string_view("")); +} + +TEST(StringViewTest, whenRemovingTooLargeSuffix_thenThrows) { + expectThrows( + [] { remove_suffix(string_view("hello"), 6); }, + "basic_string_view::remove_suffix: out of range. SuffixLength: 6, size: 5"); +} +} // namespace test_remove_suffix + +namespace test_swap_function { +CONSTEXPR_EXCEPT_GCC5 std::pair get() { + string_view first = "first"; + string_view second = "second"; + swap(first, second); + return std::make_pair(first, second); +} +TEST(StringViewTest, testSwapFunction) { +#if IS_NOT_GCC5_CONSTEXPR + static_assert(string_view("second") == get().first, ""); + static_assert(string_view("first") == get().second, ""); +#endif + + EXPECT_EQ(string_view("second"), get().first); + EXPECT_EQ(string_view("first"), get().second); +} +} // namespace test_swap_function + +namespace test_swap_method { +CONSTEXPR_EXCEPT_GCC5 std::pair get() { + string_view first = "first"; + string_view second = "second"; + first.swap(second); + return std::make_pair(first, second); +} +TEST(StringViewTest, testSwapMethod) { +#if IS_NOT_GCC5_CONSTEXPR + static_assert(string_view("second") == get().first, ""); + static_assert(string_view("first") == get().second, ""); +#endif + + EXPECT_EQ(string_view("second"), get().first); + EXPECT_EQ(string_view("first"), get().second); +} +} // namespace test_swap_method + +namespace test_copy { +TEST(StringViewTest, whenCopyingFullStringView_thenDestinationHasCorrectData) { + string_view data = "hello"; + char result[5]; + size_t num_copied = data.copy(result, 5); + EXPECT_EQ(5, num_copied); + EXPECT_TRUE(string_equal("hello", result, 5)); +} + +TEST(StringViewTest, whenCopyingSubstr_thenDestinationHasCorrectData) { + string_view data = "hello"; + char result[2]; + size_t num_copied = data.copy(result, 2, 2); + EXPECT_EQ(2, num_copied); + EXPECT_TRUE(string_equal("ll", result, 2)); +} + +TEST(StringViewTest, whenCopyingTooMuch_thenJustCopiesLess) { + string_view data = "hello"; + char result[100]; + size_t num_copied = data.copy(result, 100, 2); + EXPECT_EQ(3, num_copied); + EXPECT_TRUE(string_equal("llo", result, 3)); +} + +TEST(StringViewTest, whenCopyingJustAtRange_thenDoesntCrash) { + string_view data = "hello"; + char result[1]; + size_t num_copied = data.copy(result, 2, 5); + EXPECT_EQ(0, num_copied); +} + +TEST(StringViewTest, whenCopyingOutOfRange_thenThrows) { + string_view data = "hello"; + char result[2]; + expectThrows( + [&] { data.copy(result, 2, 6); }, + "basic_string_view::copy: out of range. Index: 6, size: 5"); +} +} // namespace test_copy + +namespace test_substr { +static_assert(string_view("").substr() == string_view(""), ""); +static_assert(string_view("").substr(0) == string_view(""), ""); +static_assert(string_view("").substr(0, 0) == string_view(""), ""); + +static_assert(string_view("hello").substr() == string_view("hello"), ""); +static_assert(string_view("hello").substr(0) == string_view("hello"), ""); +static_assert(string_view("hello").substr(1) == string_view("ello"), ""); +static_assert(string_view("hello").substr(5) == string_view(""), ""); + +static_assert(string_view("hello").substr(0, 0) == string_view(""), ""); +static_assert(string_view("hello").substr(0, 2) == string_view("he"), ""); +static_assert(string_view("hello").substr(1, 2) == string_view("el"), ""); +static_assert(string_view("hello").substr(4, 1) == string_view("o"), ""); + +static_assert(string_view("hello").substr(0, 100) == string_view("hello"), ""); +static_assert(string_view("hello").substr(1, 100) == string_view("ello"), ""); +static_assert(string_view("hello").substr(5, 100) == string_view(""), ""); + +TEST(StringViewTest, whenCallingSubstrWithPosOutOfRange_thenThrows) { + expectThrows( + [] { string_view("hello").substr(6); }, + "basic_string_view::substr parameter out of bounds. Index: 6, size: 5"); + + expectThrows( + [] { string_view("hello").substr(6, 0); }, + "basic_string_view::substr parameter out of bounds. Index: 6, size: 5"); +} +} // namespace test_substr + +namespace test_compare_overload1 { +static_assert(0 == string_view("").compare(string_view("")), ""); +static_assert(0 == string_view("a").compare(string_view("a")), ""); +static_assert(0 == string_view("hello").compare(string_view("hello")), ""); +static_assert(0 < string_view("hello").compare(string_view("")), ""); +static_assert(0 < string_view("hello").compare(string_view("aello")), ""); +static_assert(0 < string_view("hello").compare(string_view("a")), ""); +static_assert( + 0 < string_view("hello").compare(string_view("abcdefghijklmno")), + ""); +static_assert(0 < string_view("hello").compare(string_view("hela")), ""); +static_assert(0 < string_view("hello").compare(string_view("helao")), ""); +static_assert( + 0 < string_view("hello").compare(string_view("helaobcdefgh")), + ""); +static_assert(0 < string_view("hello").compare(string_view("hell")), ""); +static_assert(0 > string_view("").compare(string_view("hello")), ""); +static_assert(0 > string_view("hello").compare(string_view("zello")), ""); +static_assert(0 > string_view("hello").compare(string_view("z")), ""); +static_assert( + 0 > string_view("hello").compare(string_view("zabcdefghijklmno")), + ""); +static_assert(0 > string_view("hello").compare(string_view("helz")), ""); +static_assert(0 > string_view("hello").compare(string_view("helzo")), ""); +static_assert( + 0 > string_view("hello").compare(string_view("helzobcdefgh")), + ""); +static_assert(0 > string_view("hello").compare(string_view("helloa")), ""); +} // namespace test_compare_overload1 + +namespace test_compare_overload2 { +static_assert(0 == string_view("").compare(0, 0, string_view("")), ""); +static_assert(0 == string_view("hello").compare(2, 2, string_view("ll")), ""); +static_assert(0 < string_view("hello").compare(2, 2, string_view("l")), ""); +static_assert(0 > string_view("hello").compare(2, 2, string_view("lll")), ""); +static_assert(0 < string_view("hello").compare(2, 2, string_view("la")), ""); +static_assert(0 > string_view("hello").compare(2, 2, string_view("lz")), ""); +} // namespace test_compare_overload2 + +namespace test_compare_overload3 { +static_assert(0 == string_view("").compare(0, 0, string_view(""), 0, 0), ""); +static_assert( + 0 == string_view("hello").compare(2, 2, string_view("hello"), 2, 2), + ""); +static_assert( + 0 < string_view("hello").compare(2, 2, string_view("hello"), 2, 1), + ""); +static_assert( + 0 > string_view("hello").compare(2, 2, string_view("hello"), 2, 3), + ""); +static_assert( + 0 < string_view("hello").compare(2, 2, string_view("hellola"), 5, 2), + ""); +static_assert( + 0 > string_view("hello").compare(2, 2, string_view("hellolz"), 5, 2), + ""); +} // namespace test_compare_overload3 + +namespace test_compare_overload4 { +static_assert(0 == string_view("").compare(""), ""); +static_assert(0 == string_view("a").compare("a"), ""); +static_assert(0 == string_view("hello").compare("hello"), ""); +static_assert(0 < string_view("hello").compare(""), ""); +static_assert(0 < string_view("hello").compare("aello"), ""); +static_assert(0 < string_view("hello").compare("a"), ""); +static_assert(0 < string_view("hello").compare("abcdefghijklmno"), ""); +static_assert(0 < string_view("hello").compare("hela"), ""); +static_assert(0 < string_view("hello").compare("helao"), ""); +static_assert(0 < string_view("hello").compare("helaobcdefgh"), ""); +static_assert(0 < string_view("hello").compare("hell"), ""); +static_assert(0 > string_view("").compare("hello"), ""); +static_assert(0 > string_view("hello").compare("zello"), ""); +static_assert(0 > string_view("hello").compare("z"), ""); +static_assert(0 > string_view("hello").compare("zabcdefghijklmno"), ""); +static_assert(0 > string_view("hello").compare("helz"), ""); +static_assert(0 > string_view("hello").compare("helzo"), ""); +static_assert(0 > string_view("hello").compare("helzobcdefgh"), ""); +static_assert(0 > string_view("hello").compare("helloa"), ""); +} // namespace test_compare_overload4 + +namespace test_compare_overload5 { +static_assert(0 == string_view("").compare(0, 0, ""), ""); +static_assert(0 == string_view("hello").compare(2, 2, "ll"), ""); +static_assert(0 < string_view("hello").compare(2, 2, "l"), ""); +static_assert(0 > string_view("hello").compare(2, 2, "lll"), ""); +static_assert(0 < string_view("hello").compare(2, 2, "la"), ""); +static_assert(0 > string_view("hello").compare(2, 2, "lz"), ""); +} // namespace test_compare_overload5 + +namespace test_compare_overload6 { +static_assert(0 == string_view("").compare(0, 0, "", 0, 0), ""); +static_assert(0 == string_view("hello").compare(2, 2, "hello", 2, 2), ""); +static_assert(0 < string_view("hello").compare(2, 2, "hello", 2, 1), ""); +static_assert(0 > string_view("hello").compare(2, 2, "hello", 2, 3), ""); +static_assert(0 < string_view("hello").compare(2, 2, "hellola", 5, 2), ""); +static_assert(0 > string_view("hello").compare(2, 2, "hellolz", 5, 2), ""); +} // namespace test_compare_overload6 + +namespace test_equality_comparison { +static_assert(string_view("hi") == string_view("hi"), ""); +static_assert(!(string_view("hi") != string_view("hi")), ""); + +static_assert(string_view("") == string_view(""), ""); +static_assert(!(string_view("") != string_view("")), ""); + +static_assert(string_view("hi") != string_view("hi2"), ""); +static_assert(!(string_view("hi") == string_view("hi2")), ""); + +static_assert(string_view("hi2") != string_view("hi"), ""); +static_assert(!(string_view("hi2") == string_view("hi")), ""); + +static_assert(string_view("hi") != string_view("ha"), ""); +static_assert(!(string_view("hi") == string_view("ha")), ""); + +static_assert(string_view("ha") != string_view("hi"), ""); +static_assert(!(string_view("ha") == string_view("hi")), ""); +} // namespace test_equality_comparison + +namespace test_less_than { +static_assert(!(string_view("") < string_view("")), ""); +static_assert(!(string_view("a") < string_view("a")), ""); +static_assert(!(string_view("hello") < string_view("hello")), ""); +static_assert(!(string_view("hello") < string_view("")), ""); +static_assert(!(string_view("hello") < string_view("aello")), ""); +static_assert(!(string_view("hello") < string_view("a")), ""); +static_assert(!(string_view("hello") < string_view("abcdefghijklmno")), ""); +static_assert(!(string_view("hello") < string_view("hela")), ""); +static_assert(!(string_view("hello") < string_view("helao")), ""); +static_assert(!(string_view("hello") < string_view("helaobcdefgh")), ""); +static_assert(!(string_view("hello") < string_view("hell")), ""); +static_assert(string_view("") < string_view("hello"), ""); +static_assert(string_view("hello") < string_view("zello"), ""); +static_assert(string_view("hello") < string_view("z"), ""); +static_assert(string_view("hello") < string_view("zabcdefghijklmno"), ""); +static_assert(string_view("hello") < string_view("helz"), ""); +static_assert(string_view("hello") < string_view("helzo"), ""); +static_assert(string_view("hello") < string_view("helzobcdefgh"), ""); +static_assert(string_view("hello") < string_view("helloa"), ""); +} // namespace test_less_than + +namespace test_less_or_equal_than { +static_assert(string_view("") <= string_view(""), ""); +static_assert(string_view("a") <= string_view("a"), ""); +static_assert(string_view("hello") <= string_view("hello"), ""); +static_assert(!(string_view("hello") <= string_view("")), ""); +static_assert(!(string_view("hello") <= string_view("aello")), ""); +static_assert(!(string_view("hello") <= string_view("a")), ""); +static_assert(!(string_view("hello") <= string_view("abcdefghijklmno")), ""); +static_assert(!(string_view("hello") <= string_view("hela")), ""); +static_assert(!(string_view("hello") <= string_view("helao")), ""); +static_assert(!(string_view("hello") <= string_view("helaobcdefgh")), ""); +static_assert(!(string_view("hello") <= string_view("hell")), ""); +static_assert(string_view("") <= string_view("hello"), ""); +static_assert(string_view("hello") <= string_view("zello"), ""); +static_assert(string_view("hello") <= string_view("z"), ""); +static_assert(string_view("hello") <= string_view("zabcdefghijklmno"), ""); +static_assert(string_view("hello") <= string_view("helz"), ""); +static_assert(string_view("hello") <= string_view("helzo"), ""); +static_assert(string_view("hello") <= string_view("helzobcdefgh"), ""); +static_assert(string_view("hello") <= string_view("helloa"), ""); +} // namespace test_less_or_equal_than + +namespace test_greater_than { +static_assert(!(string_view("") > string_view("")), ""); +static_assert(!(string_view("a") > string_view("a")), ""); +static_assert(!(string_view("hello") > string_view("hello")), ""); +static_assert(string_view("hello") > string_view(""), ""); +static_assert(string_view("hello") > string_view("aello"), ""); +static_assert(string_view("hello") > string_view("a"), ""); +static_assert(string_view("hello") > string_view("abcdefghijklmno"), ""); +static_assert(string_view("hello") > string_view("hela"), ""); +static_assert(string_view("hello") > string_view("helao"), ""); +static_assert(string_view("hello") > string_view("helaobcdefgh"), ""); +static_assert(string_view("hello") > string_view("hell"), ""); +static_assert(!(string_view("") > string_view("hello")), ""); +static_assert(!(string_view("hello") > string_view("zello")), ""); +static_assert(!(string_view("hello") > string_view("z")), ""); +static_assert(!(string_view("hello") > string_view("zabcdefghijklmno")), ""); +static_assert(!(string_view("hello") > string_view("helz")), ""); +static_assert(!(string_view("hello") > string_view("helzo")), ""); +static_assert(!(string_view("hello") > string_view("helzobcdefgh")), ""); +static_assert(!(string_view("hello") > string_view("helloa")), ""); +} // namespace test_greater_than + +namespace test_greater_or_equals_than { +static_assert(string_view("") >= string_view(""), ""); +static_assert(string_view("a") >= string_view("a"), ""); +static_assert(string_view("hello") >= string_view("hello"), ""); +static_assert(string_view("hello") >= string_view(""), ""); +static_assert(string_view("hello") >= string_view("aello"), ""); +static_assert(string_view("hello") >= string_view("a"), ""); +static_assert(string_view("hello") >= string_view("abcdefghijklmno"), ""); +static_assert(string_view("hello") >= string_view("hela"), ""); +static_assert(string_view("hello") >= string_view("helao"), ""); +static_assert(string_view("hello") >= string_view("helaobcdefgh"), ""); +static_assert(string_view("hello") >= string_view("hell"), ""); +static_assert(!(string_view("") >= string_view("hello")), ""); +static_assert(!(string_view("hello") >= string_view("zello")), ""); +static_assert(!(string_view("hello") >= string_view("z")), ""); +static_assert(!(string_view("hello") >= string_view("zabcdefghijklmno")), ""); +static_assert(!(string_view("hello") >= string_view("helz")), ""); +static_assert(!(string_view("hello") >= string_view("helzo")), ""); +static_assert(!(string_view("hello") >= string_view("helzobcdefgh")), ""); +static_assert(!(string_view("hello") >= string_view("helloa")), ""); +} // namespace test_greater_or_equals_than + +namespace test_starts_with { +static_assert(string_view("hi").starts_with(string_view("hi")), ""); +static_assert(string_view("").starts_with(string_view("")), ""); +static_assert(string_view("hi2").starts_with(string_view("")), ""); +static_assert(!string_view("").starts_with(string_view("hi")), ""); +static_assert(string_view("hi2").starts_with(string_view("hi")), ""); +static_assert(!string_view("hi").starts_with(string_view("hi2")), ""); +static_assert(!string_view("hi").starts_with(string_view("ha")), ""); + +static_assert(string_view("hi").starts_with("hi"), ""); +static_assert(string_view("").starts_with(""), ""); +static_assert(string_view("hi2").starts_with(""), ""); +static_assert(!string_view("").starts_with("hi"), ""); +static_assert(string_view("hi2").starts_with("hi"), ""); +static_assert(!string_view("hi").starts_with("hi2"), ""); +static_assert(!string_view("hi").starts_with("ha"), ""); + +static_assert(!string_view("").starts_with('a'), ""); +static_assert(!string_view("").starts_with('\0'), ""); +static_assert(!string_view("hello").starts_with('a'), ""); +static_assert(string_view("hello").starts_with('h'), ""); +} // namespace test_starts_with + +namespace test_ends_with { +static_assert(string_view("hi").ends_with(string_view("hi")), ""); +static_assert(string_view("").ends_with(string_view("")), ""); +static_assert(string_view("hi2").ends_with(string_view("")), ""); +static_assert(!string_view("").ends_with(string_view("hi")), ""); +static_assert(string_view("hi2").ends_with(string_view("i2")), ""); +static_assert(!string_view("i2").ends_with(string_view("hi2")), ""); +static_assert(!string_view("hi").ends_with(string_view("ha")), ""); + +static_assert(string_view("hi").ends_with("hi"), ""); +static_assert(string_view("").ends_with(""), ""); +static_assert(string_view("hi2").ends_with(""), ""); +static_assert(!string_view("").ends_with("hi"), ""); +static_assert(string_view("hi2").ends_with("i2"), ""); +static_assert(!string_view("i2").ends_with("hi2"), ""); +static_assert(!string_view("hi").ends_with("ha"), ""); + +static_assert(!string_view("").ends_with('a'), ""); +static_assert(!string_view("").ends_with('\0'), ""); +static_assert(!string_view("hello").ends_with('a'), ""); +static_assert(string_view("hello").ends_with('o'), ""); +} // namespace test_ends_with + +namespace test_find_overload1 { +static_assert(0 == string_view("").find(string_view("")), ""); +static_assert(string_view::npos == string_view("").find(string_view("a")), ""); +static_assert( + string_view::npos == string_view("").find(string_view(""), 1), + ""); +static_assert(0 == string_view("abc").find(string_view("")), ""); +static_assert(2 == string_view("abc").find(string_view(""), 2), ""); +static_assert(0 == string_view("abc").find(string_view("a")), ""); +static_assert(0 == string_view("abc").find(string_view("ab")), ""); +static_assert(0 == string_view("abc").find(string_view("abc")), ""); +static_assert(1 == string_view("abc").find(string_view("bc")), ""); +static_assert(1 == string_view("abc").find(string_view("b")), ""); +static_assert(2 == string_view("abc").find(string_view("c")), ""); +static_assert(0 == string_view("abc").find(string_view("a")), ""); +static_assert(0 == string_view("abc").find(string_view("ab")), ""); +static_assert(0 == string_view("abc").find(string_view("abc")), ""); +static_assert(1 == string_view("ababa").find(string_view("ba")), ""); +static_assert(3 == string_view("ababa").find(string_view("ba"), 2), ""); +static_assert(3 == string_view("ababa").find(string_view("ba"), 3), ""); +static_assert( + string_view::npos == string_view("ababa").find(string_view("ba"), 4), + ""); +static_assert( + string_view::npos == string_view("abc").find(string_view("abcd")), + ""); +} // namespace test_find_overload1 + +namespace test_find_overload2 { +static_assert(string_view::npos == string_view("").find('a'), ""); +static_assert(0 == string_view("a").find('a'), ""); +static_assert(0 == string_view("abc").find('a'), ""); +static_assert(string_view::npos == string_view("a").find('a', 1), ""); +static_assert(1 == string_view("abc").find('b'), ""); +static_assert(1 == string_view("abc").find('b', 1), ""); +static_assert(string_view::npos == string_view("abc").find('b', 2), ""); +static_assert(2 == string_view("abc").find('c'), ""); +static_assert(2 == string_view("abc").find('c', 1), ""); +static_assert(2 == string_view("abc").find('c', 2), ""); +static_assert(string_view::npos == string_view("abc").find('c', 3), ""); +static_assert(string_view::npos == string_view("abc").find('a', 100), ""); +static_assert(string_view::npos == string_view("abc").find('z'), ""); +static_assert(0 == string_view("ababa").find('a'), ""); +static_assert(0 == string_view("ababa").find('a', 0), ""); +static_assert(2 == string_view("ababa").find('a', 1), ""); +static_assert(2 == string_view("ababa").find('a', 2), ""); +static_assert(4 == string_view("ababa").find('a', 3), ""); +static_assert(4 == string_view("ababa").find('a', 4), ""); +static_assert(string_view::npos == string_view("ababa").find('a', 5), ""); +} // namespace test_find_overload2 + +namespace test_find_overload3 { +static_assert(0 == string_view("").find("", 0, 0), ""); +static_assert(string_view::npos == string_view("").find("a", 0, 1), ""); +static_assert(string_view::npos == string_view("").find("", 1, 0), ""); +static_assert(0 == string_view("abc").find("", 0, 0), ""); +static_assert(2 == string_view("abc").find("", 2, 0), ""); +static_assert(0 == string_view("abc").find("a", 0, 1), ""); +static_assert(0 == string_view("abc").find("ab", 0, 2), ""); +static_assert(0 == string_view("abc").find("abc", 0, 3), ""); +static_assert(1 == string_view("abc").find("bc", 0, 2), ""); +static_assert(1 == string_view("abc").find("b", 0, 1), ""); +static_assert(2 == string_view("abc").find("c", 0, 1), ""); +static_assert(0 == string_view("abc").find("a", 0, 1), ""); +static_assert(0 == string_view("abc").find("ab", 0, 2), ""); +static_assert(0 == string_view("abc").find("abc", 0, 3), ""); +static_assert(1 == string_view("ababa").find("ba", 0, 2), ""); +static_assert(3 == string_view("ababa").find("ba", 2, 2), ""); +static_assert(3 == string_view("ababa").find("ba", 3, 2), ""); +static_assert(string_view::npos == string_view("ababa").find("ba", 4, 2), ""); +static_assert(string_view::npos == string_view("abc").find("abcd", 0, 4), ""); +} // namespace test_find_overload3 + +namespace test_find_overload4 { +static_assert(0 == string_view("").find(""), ""); +static_assert(string_view::npos == string_view("").find("a"), ""); +static_assert(string_view::npos == string_view("").find("", 1), ""); +static_assert(0 == string_view("abc").find(""), ""); +static_assert(2 == string_view("abc").find("", 2), ""); +static_assert(0 == string_view("abc").find("a"), ""); +static_assert(0 == string_view("abc").find("ab"), ""); +static_assert(0 == string_view("abc").find("abc"), ""); +static_assert(1 == string_view("abc").find("bc"), ""); +static_assert(1 == string_view("abc").find("b"), ""); +static_assert(2 == string_view("abc").find("c"), ""); +static_assert(0 == string_view("abc").find("a"), ""); +static_assert(0 == string_view("abc").find("ab"), ""); +static_assert(0 == string_view("abc").find("abc"), ""); +static_assert(1 == string_view("ababa").find("ba"), ""); +static_assert(3 == string_view("ababa").find("ba", 2), ""); +static_assert(3 == string_view("ababa").find("ba", 3), ""); +static_assert(string_view::npos == string_view("ababa").find("ba", 4), ""); +static_assert(string_view::npos == string_view("abc").find("abcd"), ""); +} // namespace test_find_overload4 + +namespace test_rfind_overload1 { +static_assert(0 == string_view("").rfind(string_view("")), ""); +static_assert(string_view::npos == string_view("").rfind(string_view("a")), ""); +static_assert(0 == string_view("").rfind(string_view(""), 1), ""); +static_assert(3 == string_view("abc").rfind(string_view("")), ""); +static_assert(0 == string_view("abc").rfind(string_view(""), 0), ""); +static_assert(0 == string_view("abc").rfind(string_view("a")), ""); +static_assert(0 == string_view("abc").rfind(string_view("ab")), ""); +static_assert(0 == string_view("abc").rfind(string_view("abc")), ""); +static_assert(1 == string_view("abc").rfind(string_view("bc")), ""); +static_assert(1 == string_view("abc").rfind(string_view("b")), ""); +static_assert(2 == string_view("abc").rfind(string_view("c")), ""); +static_assert(0 == string_view("abc").rfind(string_view("a")), ""); +static_assert(0 == string_view("abc").rfind(string_view("ab")), ""); +static_assert(0 == string_view("abc").rfind(string_view("abc")), ""); +static_assert(3 == string_view("ababa").rfind(string_view("ba")), ""); +static_assert(1 == string_view("ababa").rfind(string_view("ba"), 2), ""); +static_assert(1 == string_view("ababa").rfind(string_view("ba"), 1), ""); +static_assert( + string_view::npos == string_view("ababa").rfind(string_view("ba"), 0), + ""); +static_assert( + string_view::npos == string_view("abc").rfind(string_view("abcd")), + ""); +} // namespace test_rfind_overload1 + +namespace test_rfind_overload2 { +static_assert(string_view::npos == string_view("").rfind('a'), ""); +static_assert(0 == string_view("a").rfind('a'), ""); +static_assert(0 == string_view("abc").rfind('a'), ""); +static_assert(0 == string_view("a").rfind('a', 0), ""); +static_assert(1 == string_view("abc").rfind('b'), ""); +static_assert(string_view::npos == string_view("abc").rfind('b', 0), ""); +static_assert(1 == string_view("abc").rfind('b', 1), ""); +static_assert(2 == string_view("abc").rfind('c'), ""); +static_assert(string_view::npos == string_view("abc").rfind('c', 0), ""); +static_assert(string_view::npos == string_view("abc").rfind('c', 1), ""); +static_assert(2 == string_view("abc").rfind('c', 2), ""); +static_assert(2 == string_view("abc").rfind('c', 3), ""); +static_assert(0 == string_view("abc").rfind('a', 100), ""); +static_assert(string_view::npos == string_view("abc").rfind('z'), ""); +static_assert(4 == string_view("ababa").rfind('a'), ""); +static_assert(0 == string_view("ababa").rfind('a', 0), ""); +static_assert(0 == string_view("ababa").rfind('a', 1), ""); +static_assert(2 == string_view("ababa").rfind('a', 2), ""); +static_assert(2 == string_view("ababa").rfind('a', 3), ""); +static_assert(4 == string_view("ababa").rfind('a', 4), ""); +static_assert(4 == string_view("ababa").rfind('a', 5), ""); +} // namespace test_rfind_overload2 + +namespace test_rfind_overload3 { +static_assert(0 == string_view("").rfind("", string_view::npos, 0), ""); +static_assert( + string_view::npos == string_view("").rfind("a", string_view::npos, 1), + ""); +static_assert(0 == string_view("").rfind("", 1, 0), ""); +static_assert(3 == string_view("abc").rfind("", string_view::npos, 0), ""); +static_assert(0 == string_view("abc").rfind("", 0, 0), ""); +static_assert(0 == string_view("abc").rfind("a", string_view::npos, 1), ""); +static_assert(0 == string_view("abc").rfind("ab", string_view::npos, 2), ""); +static_assert(0 == string_view("abc").rfind("abc", string_view::npos, 3), ""); +static_assert(1 == string_view("abc").rfind("bc", string_view::npos, 2), ""); +static_assert(1 == string_view("abc").rfind("b", string_view::npos, 1), ""); +static_assert(2 == string_view("abc").rfind("c", string_view::npos, 1), ""); +static_assert(0 == string_view("abc").rfind("a", string_view::npos, 1), ""); +static_assert(0 == string_view("abc").rfind("ab", string_view::npos, 2), ""); +static_assert(0 == string_view("abc").rfind("abc", string_view::npos, 3), ""); +static_assert(3 == string_view("ababa").rfind("ba", string_view::npos, 2), ""); +static_assert(1 == string_view("ababa").rfind("ba", 2, 2), ""); +static_assert(1 == string_view("ababa").rfind("ba", 1, 2), ""); +static_assert(string_view::npos == string_view("ababa").rfind("ba", 0, 2), ""); +static_assert( + string_view::npos == string_view("abc").rfind("abcd", string_view::npos, 4), + ""); +} // namespace test_rfind_overload3 + +namespace test_rfind_overload4 { +static_assert(0 == string_view("").rfind(""), ""); +static_assert(string_view::npos == string_view("").rfind("a"), ""); +static_assert(0 == string_view("").rfind("", 1), ""); +static_assert(3 == string_view("abc").rfind(""), ""); +static_assert(0 == string_view("abc").rfind("", 0), ""); +static_assert(0 == string_view("abc").rfind("a"), ""); +static_assert(0 == string_view("abc").rfind("ab"), ""); +static_assert(0 == string_view("abc").rfind("abc"), ""); +static_assert(1 == string_view("abc").rfind("bc"), ""); +static_assert(1 == string_view("abc").rfind("b"), ""); +static_assert(2 == string_view("abc").rfind("c"), ""); +static_assert(0 == string_view("abc").rfind("a"), ""); +static_assert(0 == string_view("abc").rfind("ab"), ""); +static_assert(0 == string_view("abc").rfind("abc"), ""); +static_assert(3 == string_view("ababa").rfind("ba"), ""); +static_assert(1 == string_view("ababa").rfind("ba", 2), ""); +static_assert(1 == string_view("ababa").rfind("ba", 1), ""); +static_assert(string_view::npos == string_view("ababa").rfind("ba", 0), ""); +static_assert(string_view::npos == string_view("abc").rfind("abcd"), ""); +} // namespace test_rfind_overload4 + +namespace test_find_first_of_overload1 { +static_assert( + string_view::npos == string_view("").find_first_of(string_view("")), + ""); +static_assert( + string_view::npos == string_view("").find_first_of(string_view("a")), + ""); +static_assert( + string_view::npos == string_view("").find_first_of(string_view("abc")), + ""); +static_assert( + string_view::npos == string_view("abc").find_first_of(string_view("")), + ""); +static_assert( + string_view::npos == string_view("abc").find_first_of(string_view("d")), + ""); +static_assert( + string_view::npos == string_view("abc").find_first_of(string_view("def")), + ""); + +static_assert(0 == string_view("abcabc").find_first_of(string_view("a")), ""); +static_assert(1 == string_view("abcabc").find_first_of(string_view("b")), ""); +static_assert(2 == string_view("abcabc").find_first_of(string_view("c")), ""); +static_assert(1 == string_view("abcabc").find_first_of(string_view("bc")), ""); +static_assert(1 == string_view("abcabc").find_first_of(string_view("cbd")), ""); + +static_assert( + string_view::npos == string_view("").find_first_of(string_view(""), 1), + ""); +static_assert( + string_view::npos == string_view("").find_first_of(string_view("a"), 1), + ""); +static_assert( + string_view::npos == string_view("").find_first_of(string_view("abc"), 100), + ""); +static_assert( + string_view::npos == string_view("abc").find_first_of(string_view(""), 1), + ""); +static_assert( + string_view::npos == string_view("abc").find_first_of(string_view("d"), 3), + ""); +static_assert( + string_view::npos == + string_view("abc").find_first_of(string_view("def"), 2), + ""); + +static_assert( + 3 == string_view("abcabc").find_first_of(string_view("a"), 1), + ""); +static_assert( + 4 == string_view("abcabc").find_first_of(string_view("b"), 3), + ""); +static_assert( + 5 == string_view("abcabc").find_first_of(string_view("c"), 5), + ""); +static_assert( + 4 == string_view("abcabc").find_first_of(string_view("bc"), 3), + ""); +static_assert( + 4 == string_view("abcabc").find_first_of(string_view("cbd"), 4), + ""); +} // namespace test_find_first_of_overload1 + +namespace test_find_first_of_overload2 { +static_assert(string_view::npos == string_view("").find_first_of('a'), ""); +static_assert(0 == string_view("a").find_first_of('a'), ""); +static_assert(0 == string_view("abc").find_first_of('a'), ""); +static_assert(string_view::npos == string_view("a").find_first_of('a', 1), ""); +static_assert(1 == string_view("abc").find_first_of('b'), ""); +static_assert(1 == string_view("abc").find_first_of('b', 1), ""); +static_assert( + string_view::npos == string_view("abc").find_first_of('b', 2), + ""); +static_assert(2 == string_view("abc").find_first_of('c'), ""); +static_assert(2 == string_view("abc").find_first_of('c', 1), ""); +static_assert(2 == string_view("abc").find_first_of('c', 2), ""); +static_assert( + string_view::npos == string_view("abc").find_first_of('c', 3), + ""); +static_assert( + string_view::npos == string_view("abc").find_first_of('a', 100), + ""); +static_assert(string_view::npos == string_view("abc").find_first_of('z'), ""); +static_assert(0 == string_view("ababa").find_first_of('a'), ""); +static_assert(0 == string_view("ababa").find_first_of('a', 0), ""); +static_assert(2 == string_view("ababa").find_first_of('a', 1), ""); +static_assert(2 == string_view("ababa").find_first_of('a', 2), ""); +static_assert(4 == string_view("ababa").find_first_of('a', 3), ""); +static_assert(4 == string_view("ababa").find_first_of('a', 4), ""); +static_assert( + string_view::npos == string_view("ababa").find_first_of('a', 5), + ""); +} // namespace test_find_first_of_overload2 + +namespace test_find_first_of_overload3 { +static_assert( + string_view::npos == string_view("").find_first_of("ab", 0, 0), + ""); +static_assert( + string_view::npos == string_view("").find_first_of("abc", 0, 1), + ""); +static_assert( + string_view::npos == string_view("").find_first_of("abcdef", 0, 3), + ""); +static_assert( + string_view::npos == string_view("abc").find_first_of("abcdef", 0, 0), + ""); +static_assert( + string_view::npos == string_view("abc").find_first_of("defa", 0, 1), + ""); +static_assert( + string_view::npos == string_view("abc").find_first_of("defabc", 0, 3), + ""); + +static_assert(0 == string_view("abcabc").find_first_of("abc", 0, 1), ""); +static_assert(1 == string_view("abcabc").find_first_of("bac", 0, 1), ""); +static_assert(2 == string_view("abcabc").find_first_of("cab", 0, 1), ""); +static_assert(1 == string_view("abcabc").find_first_of("bccda", 0, 2), ""); +static_assert(1 == string_view("abcabc").find_first_of("cbdab", 0, 3), ""); + +static_assert( + string_view::npos == string_view("").find_first_of("ab", 1, 0), + ""); +static_assert( + string_view::npos == string_view("").find_first_of("abc", 1, 1), + ""); +static_assert( + string_view::npos == string_view("").find_first_of("abcdef", 100, 3), + ""); +static_assert( + string_view::npos == string_view("abc").find_first_of("abcdef", 1, 0), + ""); +static_assert( + string_view::npos == string_view("abc").find_first_of("defa", 3, 1), + ""); +static_assert( + string_view::npos == string_view("abc").find_first_of("defabc", 2, 3), + ""); + +static_assert(3 == string_view("abcabc").find_first_of("abc", 1, 1), ""); +static_assert(4 == string_view("abcabc").find_first_of("bac", 3, 1), ""); +static_assert(5 == string_view("abcabc").find_first_of("cab", 5, 1), ""); +static_assert(4 == string_view("abcabc").find_first_of("bccda", 3, 2), ""); +static_assert(4 == string_view("abcabc").find_first_of("cbdab", 4, 3), ""); +} // namespace test_find_first_of_overload3 + +namespace test_find_first_of_overload4 { +static_assert(string_view::npos == string_view("").find_first_of(""), ""); +static_assert(string_view::npos == string_view("").find_first_of("a"), ""); +static_assert(string_view::npos == string_view("").find_first_of("abc"), ""); +static_assert(string_view::npos == string_view("abc").find_first_of(""), ""); +static_assert(string_view::npos == string_view("abc").find_first_of("d"), ""); +static_assert(string_view::npos == string_view("abc").find_first_of("def"), ""); + +static_assert(0 == string_view("abcabc").find_first_of("a"), ""); +static_assert(1 == string_view("abcabc").find_first_of("b"), ""); +static_assert(2 == string_view("abcabc").find_first_of("c"), ""); +static_assert(1 == string_view("abcabc").find_first_of("bc"), ""); +static_assert(1 == string_view("abcabc").find_first_of("cbd"), ""); + +static_assert(string_view::npos == string_view("").find_first_of("", 1), ""); +static_assert(string_view::npos == string_view("").find_first_of("a", 1), ""); +static_assert( + string_view::npos == string_view("").find_first_of("abc", 100), + ""); +static_assert(string_view::npos == string_view("abc").find_first_of("", 1), ""); +static_assert( + string_view::npos == string_view("abc").find_first_of("d", 3), + ""); +static_assert( + string_view::npos == string_view("abc").find_first_of("def", 2), + ""); + +static_assert(3 == string_view("abcabc").find_first_of("a", 1), ""); +static_assert(4 == string_view("abcabc").find_first_of("b", 3), ""); +static_assert(5 == string_view("abcabc").find_first_of("c", 5), ""); +static_assert(4 == string_view("abcabc").find_first_of("bc", 3), ""); +static_assert(4 == string_view("abcabc").find_first_of("cbd", 4), ""); +} // namespace test_find_first_of_overload4 + +namespace test_find_last_of_overload1 { +static_assert( + string_view::npos == string_view("").find_last_of(string_view("")), + ""); +static_assert( + string_view::npos == string_view("").find_last_of(string_view("a")), + ""); +static_assert( + string_view::npos == string_view("").find_last_of(string_view("abc")), + ""); +static_assert( + string_view::npos == string_view("abc").find_last_of(string_view("")), + ""); +static_assert( + string_view::npos == string_view("abc").find_last_of(string_view("d")), + ""); +static_assert( + string_view::npos == string_view("abc").find_last_of(string_view("def")), + ""); + +static_assert(3 == string_view("abcabc").find_last_of(string_view("a")), ""); +static_assert(4 == string_view("abcabc").find_last_of(string_view("b")), ""); +static_assert(5 == string_view("abcabc").find_last_of(string_view("c")), ""); +static_assert(5 == string_view("abcabc").find_last_of(string_view("bc")), ""); +static_assert(5 == string_view("abcabc").find_last_of(string_view("cbd")), ""); + +static_assert( + string_view::npos == string_view("").find_last_of(string_view(""), 1), + ""); +static_assert( + string_view::npos == string_view("").find_last_of(string_view("a"), 0), + ""); +static_assert( + string_view::npos == string_view("").find_last_of(string_view("abc"), 100), + ""); +static_assert( + string_view::npos == string_view("abc").find_last_of(string_view(""), 1), + ""); +static_assert( + string_view::npos == string_view("abc").find_last_of(string_view("d"), 3), + ""); +static_assert( + string_view::npos == string_view("abc").find_last_of(string_view("def"), 2), + ""); + +static_assert(0 == string_view("abcabc").find_last_of(string_view("a"), 2), ""); +static_assert(1 == string_view("abcabc").find_last_of(string_view("b"), 3), ""); +static_assert(2 == string_view("abcabc").find_last_of(string_view("c"), 2), ""); +static_assert( + 2 == string_view("abcabc").find_last_of(string_view("bc"), 3), + ""); +static_assert( + 2 == string_view("abcabc").find_last_of(string_view("cbd"), 2), + ""); +} // namespace test_find_last_of_overload1 + +namespace test_find_last_of_overload2 { +static_assert(string_view::npos == string_view("").find_last_of('a'), ""); +static_assert(0 == string_view("a").find_last_of('a'), ""); +static_assert(0 == string_view("abc").find_last_of('a'), ""); +static_assert(0 == string_view("a").find_last_of('a', 0), ""); +static_assert(1 == string_view("abc").find_last_of('b'), ""); +static_assert(string_view::npos == string_view("abc").find_last_of('b', 0), ""); +static_assert(1 == string_view("abc").find_last_of('b', 1), ""); +static_assert(2 == string_view("abc").find_last_of('c'), ""); +static_assert(string_view::npos == string_view("abc").find_last_of('c', 0), ""); +static_assert(string_view::npos == string_view("abc").find_last_of('c', 1), ""); +static_assert(2 == string_view("abc").find_last_of('c', 2), ""); +static_assert(2 == string_view("abc").find_last_of('c', 3), ""); +static_assert(0 == string_view("abc").find_last_of('a', 100), ""); +static_assert(string_view::npos == string_view("abc").find_last_of('z'), ""); +static_assert(4 == string_view("ababa").find_last_of('a'), ""); +static_assert(0 == string_view("ababa").find_last_of('a', 0), ""); +static_assert(0 == string_view("ababa").find_last_of('a', 1), ""); +static_assert(2 == string_view("ababa").find_last_of('a', 2), ""); +static_assert(2 == string_view("ababa").find_last_of('a', 3), ""); +static_assert(4 == string_view("ababa").find_last_of('a', 4), ""); +static_assert(4 == string_view("ababa").find_last_of('a', 5), ""); +} // namespace test_find_last_of_overload2 + +namespace test_find_last_of_overload3 { +static_assert( + string_view::npos == + string_view("").find_last_of("ab", string_view::npos, 0), + ""); +static_assert( + string_view::npos == + string_view("").find_last_of("abc", string_view::npos, 1), + ""); +static_assert( + string_view::npos == + string_view("").find_last_of("abcdef", string_view::npos, 3), + ""); +static_assert( + string_view::npos == + string_view("abc").find_last_of("abcdef", string_view::npos, 0), + ""); +static_assert( + string_view::npos == + string_view("abc").find_last_of("defa", string_view::npos, 1), + ""); +static_assert( + string_view::npos == + string_view("abc").find_last_of("defcba", string_view::npos, 3), + ""); + +static_assert( + 3 == string_view("abcabc").find_last_of("abc", string_view::npos, 1), + ""); +static_assert( + 4 == string_view("abcabc").find_last_of("bca", string_view::npos, 1), + ""); +static_assert( + 5 == string_view("abcabc").find_last_of("cab", string_view::npos, 1), + ""); +static_assert( + 5 == string_view("abcabc").find_last_of("bcab", string_view::npos, 2), + ""); +static_assert( + 5 == string_view("abcabc").find_last_of("cbdac", string_view::npos, 3), + ""); + +static_assert( + string_view::npos == string_view("").find_last_of("ab", 1, 0), + ""); +static_assert( + string_view::npos == string_view("").find_last_of("abc", 0, 1), + ""); +static_assert( + string_view::npos == string_view("").find_last_of("abcdef", 100, 3), + ""); +static_assert( + string_view::npos == string_view("abc").find_last_of("abcdef", 1, 0), + ""); +static_assert( + string_view::npos == string_view("abc").find_last_of("defa", 3, 1), + ""); +static_assert( + string_view::npos == string_view("abc").find_last_of("defcba", 2, 3), + ""); + +static_assert(0 == string_view("abcabc").find_last_of("abc", 2, 1), ""); +static_assert(1 == string_view("abcabc").find_last_of("bca", 3, 1), ""); +static_assert(2 == string_view("abcabc").find_last_of("cab", 2, 1), ""); +static_assert(2 == string_view("abcabc").find_last_of("bcab", 3, 2), ""); +static_assert(2 == string_view("abcabc").find_last_of("cbdac", 2, 2), ""); +} // namespace test_find_last_of_overload3 + +namespace test_find_last_of_overload4 { +static_assert(string_view::npos == string_view("").find_last_of(""), ""); +static_assert(string_view::npos == string_view("").find_last_of("a"), ""); +static_assert(string_view::npos == string_view("").find_last_of("abc"), ""); +static_assert(string_view::npos == string_view("abc").find_last_of(""), ""); +static_assert(string_view::npos == string_view("abc").find_last_of("d"), ""); +static_assert(string_view::npos == string_view("abc").find_last_of("def"), ""); + +static_assert(3 == string_view("abcabc").find_last_of("a"), ""); +static_assert(4 == string_view("abcabc").find_last_of("b"), ""); +static_assert(5 == string_view("abcabc").find_last_of("c"), ""); +static_assert(5 == string_view("abcabc").find_last_of("bc"), ""); +static_assert(5 == string_view("abcabc").find_last_of("cbd"), ""); + +static_assert(string_view::npos == string_view("").find_last_of("", 1), ""); +static_assert(string_view::npos == string_view("").find_last_of("a", 0), ""); +static_assert( + string_view::npos == string_view("").find_last_of("abc", 100), + ""); +static_assert(string_view::npos == string_view("abc").find_last_of("", 1), ""); +static_assert(string_view::npos == string_view("abc").find_last_of("d", 3), ""); +static_assert( + string_view::npos == string_view("abc").find_last_of("def", 2), + ""); + +static_assert(0 == string_view("abcabc").find_last_of("a", 2), ""); +static_assert(1 == string_view("abcabc").find_last_of("b", 3), ""); +static_assert(2 == string_view("abcabc").find_last_of("c", 2), ""); +static_assert(2 == string_view("abcabc").find_last_of("bc", 3), ""); +static_assert(2 == string_view("abcabc").find_last_of("cbd", 2), ""); +} // namespace test_find_last_of_overload4 + +namespace test_find_first_not_of_overload1 { +static_assert( + string_view::npos == string_view("").find_first_not_of(string_view("")), + ""); +static_assert( + string_view::npos == string_view("").find_first_not_of(string_view("a")), + ""); +static_assert( + string_view::npos == string_view("").find_first_not_of(string_view("abc")), + ""); +static_assert( + string_view::npos == + string_view("abc").find_first_not_of(string_view("abc")), + ""); +static_assert( + string_view::npos == + string_view("abc").find_first_not_of(string_view("acdb")), + ""); +static_assert( + string_view::npos == + string_view("abc").find_first_not_of(string_view("defabc")), + ""); + +static_assert( + 0 == string_view("abcabc").find_first_not_of(string_view("")), + ""); +static_assert( + 0 == string_view("abcabc").find_first_not_of(string_view("bc")), + ""); +static_assert( + 1 == string_view("abcabc").find_first_not_of(string_view("ac")), + ""); +static_assert( + 2 == string_view("abcabc").find_first_not_of(string_view("ab")), + ""); +static_assert( + 1 == string_view("abcabc").find_first_not_of(string_view("a")), + ""); +static_assert( + 1 == string_view("abcabc").find_first_not_of(string_view("da")), + ""); + +static_assert( + string_view::npos == string_view("").find_first_not_of(string_view(""), 1), + ""); +static_assert( + string_view::npos == string_view("").find_first_not_of(string_view("a"), 1), + ""); +static_assert( + string_view::npos == + string_view("").find_first_not_of(string_view("abc"), 100), + ""); +static_assert( + string_view::npos == + string_view("abc").find_first_not_of(string_view("abc"), 1), + ""); +static_assert( + string_view::npos == + string_view("abc").find_first_not_of(string_view("acdb"), 3), + ""); +static_assert( + string_view::npos == + string_view("abc").find_first_not_of(string_view("defabc"), 2), + ""); + +static_assert( + 1 == string_view("abcabc").find_first_not_of(string_view(""), 1), + ""); +static_assert( + 3 == string_view("abcabc").find_first_not_of(string_view("bc"), 1), + ""); +static_assert( + 4 == string_view("abcabc").find_first_not_of(string_view("ac"), 4), + ""); +static_assert( + 5 == string_view("abcabc").find_first_not_of(string_view("ab"), 5), + ""); +static_assert( + 4 == string_view("abcabc").find_first_not_of(string_view("a"), 3), + ""); +static_assert( + 4 == string_view("abcabc").find_first_not_of(string_view("da"), 4), + ""); +} // namespace test_find_first_not_of_overload1 + +namespace test_find_first_not_of_overload2 { +static_assert(string_view::npos == string_view("").find_first_not_of('a'), ""); +static_assert(string_view::npos == string_view("a").find_first_not_of('a'), ""); +static_assert(1 == string_view("abc").find_first_not_of('a'), ""); +static_assert( + string_view::npos == string_view("a").find_first_not_of('a', 1), + ""); +static_assert(0 == string_view("abc").find_first_not_of('b'), ""); +static_assert(2 == string_view("abc").find_first_not_of('b', 1), ""); +static_assert(2 == string_view("abc").find_first_not_of('b', 2), ""); +static_assert( + string_view::npos == string_view("abc").find_first_not_of('b', 3), + ""); +static_assert(0 == string_view("abc").find_first_not_of('c'), ""); +static_assert(1 == string_view("abc").find_first_not_of('c', 1), ""); +static_assert( + string_view::npos == string_view("abc").find_first_not_of('c', 2), + ""); +static_assert( + string_view::npos == string_view("abc").find_first_not_of('c', 3), + ""); +static_assert( + string_view::npos == string_view("abc").find_first_not_of('a', 100), + ""); +static_assert(1 == string_view("ababa").find_first_not_of('a'), ""); +static_assert(1 == string_view("ababa").find_first_not_of('a', 0), ""); +static_assert(1 == string_view("ababa").find_first_not_of('a', 1), ""); +static_assert(3 == string_view("ababa").find_first_not_of('a', 2), ""); +static_assert(3 == string_view("ababa").find_first_not_of('a', 3), ""); +static_assert( + string_view::npos == string_view("ababa").find_first_not_of('a', 4), + ""); +static_assert( + string_view::npos == string_view("ababa").find_first_not_of('a', 5), + ""); +} // namespace test_find_first_not_of_overload2 + +namespace test_find_first_not_of_overload3 { +static_assert( + string_view::npos == string_view("").find_first_not_of("ab", 0, 0), + ""); +static_assert( + string_view::npos == string_view("").find_first_not_of("abc", 0, 1), + ""); +static_assert( + string_view::npos == string_view("").find_first_not_of("abcdef", 0, 3), + ""); +static_assert( + string_view::npos == string_view("abc").find_first_not_of("abcdef", 0, 3), + ""); +static_assert( + string_view::npos == string_view("abc").find_first_not_of("acdbef", 0, 4), + ""); +static_assert( + string_view::npos == string_view("abc").find_first_not_of("defabcas", 0, 6), + ""); + +static_assert(0 == string_view("abcabc").find_first_not_of("abc", 0, 0), ""); +static_assert(0 == string_view("abcabc").find_first_not_of("bca", 0, 2), ""); +static_assert(1 == string_view("abcabc").find_first_not_of("acb", 0, 2), ""); +static_assert(2 == string_view("abcabc").find_first_not_of("abc", 0, 2), ""); +static_assert(1 == string_view("abcabc").find_first_not_of("abac", 0, 1), ""); +static_assert(1 == string_view("abcabc").find_first_not_of("dadab", 0, 2), ""); + +static_assert( + string_view::npos == string_view("").find_first_not_of("ab", 1, 0), + ""); +static_assert( + string_view::npos == string_view("").find_first_not_of("abc", 1, 1), + ""); +static_assert( + string_view::npos == string_view("").find_first_not_of("abcdef", 100, 3), + ""); +static_assert( + string_view::npos == string_view("abc").find_first_not_of("abcdef", 1, 3), + ""); +static_assert( + string_view::npos == string_view("abc").find_first_not_of("acdbef", 3, 4), + ""); +static_assert( + string_view::npos == string_view("abc").find_first_not_of("defabcas", 2, 6), + ""); + +static_assert(1 == string_view("abcabc").find_first_not_of("bca", 1, 0), ""); +static_assert(3 == string_view("abcabc").find_first_not_of("bca", 1, 2), ""); +static_assert(4 == string_view("abcabc").find_first_not_of("acb", 4, 2), ""); +static_assert(5 == string_view("abcabc").find_first_not_of("abc", 5, 2), ""); +static_assert(4 == string_view("abcabc").find_first_not_of("abac", 3, 1), ""); +static_assert(4 == string_view("abcabc").find_first_not_of("dadab", 4, 2), ""); +} // namespace test_find_first_not_of_overload3 + +namespace test_find_first_not_of_overload4 { +static_assert(string_view::npos == string_view("").find_first_not_of(""), ""); +static_assert(string_view::npos == string_view("").find_first_not_of("a"), ""); +static_assert( + string_view::npos == string_view("").find_first_not_of("abc"), + ""); +static_assert( + string_view::npos == string_view("abc").find_first_not_of("abc"), + ""); +static_assert( + string_view::npos == string_view("abc").find_first_not_of("acdb"), + ""); +static_assert( + string_view::npos == string_view("abc").find_first_not_of("defabc"), + ""); + +static_assert(0 == string_view("abcabc").find_first_not_of(""), ""); +static_assert(0 == string_view("abcabc").find_first_not_of("bc"), ""); +static_assert(1 == string_view("abcabc").find_first_not_of("ac"), ""); +static_assert(2 == string_view("abcabc").find_first_not_of("ab"), ""); +static_assert(1 == string_view("abcabc").find_first_not_of("a"), ""); +static_assert(1 == string_view("abcabc").find_first_not_of("da"), ""); + +static_assert( + string_view::npos == string_view("").find_first_not_of("", 1), + ""); +static_assert( + string_view::npos == string_view("").find_first_not_of("a", 1), + ""); +static_assert( + string_view::npos == string_view("").find_first_not_of("abc", 100), + ""); +static_assert( + string_view::npos == string_view("abc").find_first_not_of("abc", 1), + ""); +static_assert( + string_view::npos == string_view("abc").find_first_not_of("acdb", 3), + ""); +static_assert( + string_view::npos == string_view("abc").find_first_not_of("defabc", 2), + ""); + +static_assert(1 == string_view("abcabc").find_first_not_of("", 1), ""); +static_assert(3 == string_view("abcabc").find_first_not_of("bc", 1), ""); +static_assert(4 == string_view("abcabc").find_first_not_of("ac", 4), ""); +static_assert(5 == string_view("abcabc").find_first_not_of("ab", 5), ""); +static_assert(4 == string_view("abcabc").find_first_not_of("a", 3), ""); +static_assert(4 == string_view("abcabc").find_first_not_of("da", 4), ""); +} // namespace test_find_first_not_of_overload4 + +namespace test_find_last_not_of_overload1 { +static_assert( + string_view::npos == string_view("").find_last_not_of(string_view("")), + ""); +static_assert( + string_view::npos == string_view("").find_last_not_of(string_view("a")), + ""); +static_assert( + string_view::npos == string_view("").find_last_not_of(string_view("abc")), + ""); +static_assert( + string_view::npos == + string_view("abc").find_last_not_of(string_view("abc")), + ""); +static_assert( + string_view::npos == + string_view("abc").find_last_not_of(string_view("acdb")), + ""); +static_assert( + string_view::npos == + string_view("abc").find_last_not_of(string_view("defabc")), + ""); + +static_assert(5 == string_view("abcabc").find_last_not_of(string_view("")), ""); +static_assert( + 3 == string_view("abcabc").find_last_not_of(string_view("bc")), + ""); +static_assert( + 4 == string_view("abcabc").find_last_not_of(string_view("ac")), + ""); +static_assert( + 5 == string_view("abcabc").find_last_not_of(string_view("ab")), + ""); +static_assert( + 4 == string_view("abcabc").find_last_not_of(string_view("c")), + ""); +static_assert( + 4 == string_view("abcabc").find_last_not_of(string_view("ca")), + ""); + +static_assert( + string_view::npos == string_view("").find_last_not_of(string_view(""), 1), + ""); +static_assert( + string_view::npos == string_view("").find_last_not_of(string_view("a"), 0), + ""); +static_assert( + string_view::npos == + string_view("").find_last_not_of(string_view("abc"), 100), + ""); +static_assert( + string_view::npos == + string_view("abc").find_last_not_of(string_view("abc"), 1), + ""); +static_assert( + string_view::npos == + string_view("abc").find_last_not_of(string_view("acdb"), 3), + ""); +static_assert( + string_view::npos == + string_view("abc").find_last_not_of(string_view("defabc"), 2), + ""); + +static_assert( + 4 == string_view("abcabc").find_last_not_of(string_view(""), 4), + ""); +static_assert( + 0 == string_view("abcabc").find_last_not_of(string_view("bc"), 2), + ""); +static_assert( + 1 == string_view("abcabc").find_last_not_of(string_view("ac"), 2), + ""); +static_assert( + 2 == string_view("abcabc").find_last_not_of(string_view("ab"), 2), + ""); +static_assert( + 4 == string_view("abcabc").find_last_not_of(string_view("c"), 4), + ""); +static_assert( + 1 == string_view("abcabc").find_last_not_of(string_view("ca"), 2), + ""); +} // namespace test_find_last_not_of_overload1 + +namespace test_find_last_not_of_overload2 { +static_assert(string_view::npos == string_view("").find_last_not_of('a'), ""); +static_assert(string_view::npos == string_view("a").find_last_not_of('a'), ""); +static_assert(2 == string_view("abc").find_last_not_of('a'), ""); +static_assert(1 == string_view("abc").find_last_not_of('c'), ""); +static_assert( + string_view::npos == string_view("a").find_last_not_of('a', 0), + ""); +static_assert(2 == string_view("abc").find_last_not_of('b'), ""); +static_assert( + string_view::npos == string_view("abc").find_last_not_of('a', 0), + ""); +static_assert(0 == string_view("abc").find_last_not_of('b', 1), ""); +static_assert(0 == string_view("abc").find_last_not_of('c', 0), ""); +static_assert(1 == string_view("abc").find_last_not_of('c', 1), ""); +static_assert(1 == string_view("abc").find_last_not_of('c', 2), ""); +static_assert(1 == string_view("abc").find_last_not_of('c', 3), ""); +static_assert(2 == string_view("abc").find_last_not_of('a', 100), ""); +static_assert(3 == string_view("ababa").find_last_not_of('a'), ""); +static_assert( + string_view::npos == string_view("ababa").find_last_not_of('a', 0), + ""); +static_assert(1 == string_view("ababa").find_last_not_of('a', 1), ""); +static_assert(1 == string_view("ababa").find_last_not_of('a', 2), ""); +static_assert(3 == string_view("ababa").find_last_not_of('a', 3), ""); +static_assert(3 == string_view("ababa").find_last_not_of('a', 4), ""); +static_assert(3 == string_view("ababa").find_last_not_of('a', 5), ""); +} // namespace test_find_last_not_of_overload2 + +namespace test_find_last_not_of_overload3 { +static_assert( + string_view::npos == + string_view("").find_last_not_of("ab", string_view::npos, 0), + ""); +static_assert( + string_view::npos == + string_view("").find_last_not_of("abc", string_view::npos, 1), + ""); +static_assert( + string_view::npos == + string_view("").find_last_not_of("abcdef", string_view::npos, 3), + ""); +static_assert( + string_view::npos == + string_view("abc").find_last_not_of("abcdef", string_view::npos, 3), + ""); +static_assert( + string_view::npos == + string_view("abc").find_last_not_of("acdbef", string_view::npos, 4), + ""); +static_assert( + string_view::npos == + string_view("abc").find_last_not_of("defabcas", string_view::npos, 6), + ""); + +static_assert( + 5 == string_view("abcabc").find_last_not_of("cab", string_view::npos, 0), + ""); +static_assert( + 3 == string_view("abcabc").find_last_not_of("bca", string_view::npos, 2), + ""); +static_assert( + 4 == string_view("abcabc").find_last_not_of("acb", string_view::npos, 2), + ""); +static_assert( + 5 == string_view("abcabc").find_last_not_of("abc", string_view::npos, 2), + ""); +static_assert( + 4 == string_view("abcabc").find_last_not_of("caba", string_view::npos, 1), + ""); +static_assert( + 4 == string_view("abcabc").find_last_not_of("cacab", string_view::npos, 2), + ""); + +static_assert( + string_view::npos == string_view("").find_last_not_of("ab", 1, 0), + ""); +static_assert( + string_view::npos == string_view("").find_last_not_of("abc", 0, 1), + ""); +static_assert( + string_view::npos == string_view("").find_last_not_of("abcdef", 100, 3), + ""); +static_assert( + string_view::npos == string_view("abc").find_last_not_of("abcdef", 1, 3), + ""); +static_assert( + string_view::npos == string_view("abc").find_last_not_of("acdbef", 3, 4), + ""); +static_assert( + string_view::npos == string_view("abc").find_last_not_of("defabcas", 2, 6), + ""); + +static_assert(4 == string_view("abcabc").find_last_not_of("bca", 4, 0), ""); +static_assert(0 == string_view("abcabc").find_last_not_of("bca", 2, 2), ""); +static_assert(1 == string_view("abcabc").find_last_not_of("acb", 2, 2), ""); +static_assert(2 == string_view("abcabc").find_last_not_of("abc", 2, 2), ""); +static_assert(4 == string_view("abcabc").find_last_not_of("caba", 4, 1), ""); +static_assert(1 == string_view("abcabc").find_last_not_of("cacab", 2, 2), ""); +} // namespace test_find_last_not_of_overload3 + +namespace test_find_last_not_of_overload4 { +static_assert(string_view::npos == string_view("").find_last_not_of(""), ""); +static_assert(string_view::npos == string_view("").find_last_not_of("a"), ""); +static_assert(string_view::npos == string_view("").find_last_not_of("abc"), ""); +static_assert( + string_view::npos == string_view("abc").find_last_not_of("abc"), + ""); +static_assert( + string_view::npos == string_view("abc").find_last_not_of("acdb"), + ""); +static_assert( + string_view::npos == string_view("abc").find_last_not_of("defabc"), + ""); + +static_assert(5 == string_view("abcabc").find_last_not_of(""), ""); +static_assert(3 == string_view("abcabc").find_last_not_of("bc"), ""); +static_assert(4 == string_view("abcabc").find_last_not_of("ac"), ""); +static_assert(5 == string_view("abcabc").find_last_not_of("ab"), ""); +static_assert(4 == string_view("abcabc").find_last_not_of("c"), ""); +static_assert(4 == string_view("abcabc").find_last_not_of("ca"), ""); + +static_assert(string_view::npos == string_view("").find_last_not_of("", 1), ""); +static_assert( + string_view::npos == string_view("").find_last_not_of("a", 0), + ""); +static_assert( + string_view::npos == string_view("").find_last_not_of("abc", 100), + ""); +static_assert( + string_view::npos == string_view("abc").find_last_not_of("abc", 1), + ""); +static_assert( + string_view::npos == string_view("abc").find_last_not_of("acdb", 3), + ""); +static_assert( + string_view::npos == string_view("abc").find_last_not_of("defabc", 2), + ""); + +static_assert(4 == string_view("abcabc").find_last_not_of("", 4), ""); +static_assert(0 == string_view("abcabc").find_last_not_of("bc", 2), ""); +static_assert(1 == string_view("abcabc").find_last_not_of("ac", 2), ""); +static_assert(2 == string_view("abcabc").find_last_not_of("ab", 2), ""); +static_assert(4 == string_view("abcabc").find_last_not_of("c", 4), ""); +static_assert(1 == string_view("abcabc").find_last_not_of("ca", 2), ""); +} // namespace test_find_last_not_of_overload4 + +namespace test_output_operator { +void testOutputIterator(const std::string& str) { + std::ostringstream stream; + stream << string_view(str); + std::string actual = stream.str(); + EXPECT_EQ(str, actual); +} + +TEST(StringViewTest, testOutputOperator) { + testOutputIterator(""); + testOutputIterator("abc"); +} +} // namespace test_output_operator + +namespace test_hash { +TEST(StringViewTest, testHash) { + EXPECT_EQ( + std::hash()(string_view()), std::hash()("")); + EXPECT_EQ( + std::hash()(string_view("hello")), + std::hash()("hello")); + EXPECT_NE( + std::hash()(string_view("hello")), + std::hash()("")); +} +} // namespace test_hash + +} // namespace diff --git a/c10/util/C++17.h b/c10/util/C++17.h index d1290f123a2..6b74c7ae11f 100644 --- a/c10/util/C++17.h +++ b/c10/util/C++17.h @@ -294,6 +294,15 @@ template inline std::string to_string(T value) { return detail::to_string_::call(value); } +template +constexpr const T& min(const T& a, const T& b) { + return (b < a) ? b : a; +} + +template +constexpr const T& max(const T& a, const T& b) { + return (a < b) ? b : a; +} }} #endif // C10_UTIL_CPP17_H_ diff --git a/c10/util/reverse_iterator.h b/c10/util/reverse_iterator.h new file mode 100644 index 00000000000..83ae90eaaec --- /dev/null +++ b/c10/util/reverse_iterator.h @@ -0,0 +1,295 @@ +#pragma once + +/** + * A constexpr std::reverse_iterator for C++11. + * Implementation taken from libstdc++, + * https://raw.githubusercontent.com/gcc-mirror/gcc/gcc-9_2_0-release/libstdc%2B%2B-v3/include/bits/stl_iterator.h + * adapted to our code base and constexpr'ified. + */ + +// Copyright (C) 2001-2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1996-1998 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + */ + +#include +#include + +namespace c10 { + +template +class reverse_iterator + : public std::iterator< + typename std::iterator_traits<_Iterator>::iterator_category, + typename std::iterator_traits<_Iterator>::value_type, + typename std::iterator_traits<_Iterator>::difference_type, + typename std::iterator_traits<_Iterator>::pointer, + typename std::iterator_traits<_Iterator>::reference> { + protected: + _Iterator current; + + using __traits_type = std::iterator_traits<_Iterator>; + + public: + using iterator_type = _Iterator; + using difference_type = typename __traits_type::difference_type; + using pointer = typename __traits_type::pointer; + using reference = typename __traits_type::reference; + + constexpr reverse_iterator() : current() {} + + explicit constexpr reverse_iterator(iterator_type __x) : current(__x) {} + + constexpr reverse_iterator(const reverse_iterator& __x) + : current(__x.current) {} + + AT_CPP14_CONSTEXPR reverse_iterator& operator=( + const reverse_iterator& rhs) noexcept { + current = rhs.current; + } + + template + constexpr reverse_iterator(const reverse_iterator<_Iter>& __x) + : current(__x.base()) {} + + constexpr iterator_type base() const { + return current; + } + + constexpr reference operator*() const { +#if defined(__cpp_constexpr) && __cpp_constexpr >= 201304 + _Iterator iter = current; + return *--iter; +#else + // Only works for random access iterators if we're not C++14 :( + return *(current - 1); +#endif + } + + constexpr pointer operator->() const { +#if defined(__cpp_constexpr) && __cpp_constexpr >= 201304 + _Iterator iter = current; + return _S_to_pointer(--iter); +#else + // Only works for random access iterators if we're not C++14 :( + return _S_to_pointer(current - 1); +#endif + } + + AT_CPP14_CONSTEXPR reverse_iterator& operator++() { + --current; + return *this; + } + + AT_CPP14_CONSTEXPR reverse_iterator operator++(int) { + reverse_iterator __tmp = *this; + --current; + return __tmp; + } + + AT_CPP14_CONSTEXPR reverse_iterator& operator--() { + ++current; + return *this; + } + + AT_CPP14_CONSTEXPR reverse_iterator operator--(int) { + reverse_iterator __tmp = *this; + ++current; + return __tmp; + } + + constexpr reverse_iterator operator+(difference_type __n) const { + return reverse_iterator(current - __n); + } + + AT_CPP14_CONSTEXPR reverse_iterator& operator+=(difference_type __n) { + current -= __n; + return *this; + } + + constexpr reverse_iterator operator-(difference_type __n) const { + return reverse_iterator(current + __n); + } + + AT_CPP14_CONSTEXPR reverse_iterator& operator-=(difference_type __n) { + current += __n; + return *this; + } + + constexpr reference operator[](difference_type __n) const { + return *(*this + __n); + } + + private: + template + static constexpr _Tp* _S_to_pointer(_Tp* __p) { + return __p; + } + + template + static constexpr pointer _S_to_pointer(_Tp __t) { + return __t.operator->(); + } +}; + +template +inline constexpr bool operator==( + const reverse_iterator<_Iterator>& __x, + const reverse_iterator<_Iterator>& __y) { + return __x.base() == __y.base(); +} + +template +inline constexpr bool operator<( + const reverse_iterator<_Iterator>& __x, + const reverse_iterator<_Iterator>& __y) { + return __y.base() < __x.base(); +} + +template +inline constexpr bool operator!=( + const reverse_iterator<_Iterator>& __x, + const reverse_iterator<_Iterator>& __y) { + return !(__x == __y); +} + +template +inline constexpr bool operator>( + const reverse_iterator<_Iterator>& __x, + const reverse_iterator<_Iterator>& __y) { + return __y < __x; +} + +template +inline constexpr bool operator<=( + const reverse_iterator<_Iterator>& __x, + const reverse_iterator<_Iterator>& __y) { + return !(__y < __x); +} + +template +inline constexpr bool operator>=( + const reverse_iterator<_Iterator>& __x, + const reverse_iterator<_Iterator>& __y) { + return !(__x < __y); +} + +template +inline constexpr bool operator==( + const reverse_iterator<_IteratorL>& __x, + const reverse_iterator<_IteratorR>& __y) { + return __x.base() == __y.base(); +} + +template +inline constexpr bool operator<( + const reverse_iterator<_IteratorL>& __x, + const reverse_iterator<_IteratorR>& __y) { + return __y.base() < __x.base(); +} + +template +inline constexpr bool operator!=( + const reverse_iterator<_IteratorL>& __x, + const reverse_iterator<_IteratorR>& __y) { + return !(__x == __y); +} + +template +inline constexpr bool operator>( + const reverse_iterator<_IteratorL>& __x, + const reverse_iterator<_IteratorR>& __y) { + return __y < __x; +} + +template +inline constexpr bool operator<=( + const reverse_iterator<_IteratorL>& __x, + const reverse_iterator<_IteratorR>& __y) { + return !(__y < __x); +} + +template +inline constexpr bool operator>=( + const reverse_iterator<_IteratorL>& __x, + const reverse_iterator<_IteratorR>& __y) { + return !(__x < __y); +} + +template +inline constexpr auto operator-( + const reverse_iterator<_IteratorL>& __x, + const reverse_iterator<_IteratorR>& __y) + -> decltype(__y.base() - __x.base()) { + return __y.base() - __x.base(); +} + +template +inline constexpr reverse_iterator<_Iterator> operator+( + typename reverse_iterator<_Iterator>::difference_type __n, + const reverse_iterator<_Iterator>& __x) { + return reverse_iterator<_Iterator>(__x.base() - __n); +} + +template +inline constexpr reverse_iterator<_Iterator> __make_reverse_iterator( + _Iterator __i) { + return reverse_iterator<_Iterator>(__i); +} + +template +inline constexpr reverse_iterator<_Iterator> make_reverse_iterator( + _Iterator __i) { + return reverse_iterator<_Iterator>(__i); +} + +template +auto __niter_base(reverse_iterator<_Iterator> __it) + -> decltype(__make_reverse_iterator(__niter_base(__it.base()))) { + return __make_reverse_iterator(__niter_base(__it.base())); +} + +} // namespace c10 diff --git a/c10/util/string_view.h b/c10/util/string_view.h new file mode 100644 index 00000000000..3eb9dad2e96 --- /dev/null +++ b/c10/util/string_view.h @@ -0,0 +1,677 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace c10 { + +/** + * Reimplementation of std::string_view for C++11. + * Implemented following the interface definition in + * https://en.cppreference.com/w/cpp/string/basic_string_view + * See there for the API documentation. + * + * Difference: We don't have a Traits template parameter because + * std::char_traits isn't constexpr and we'd have to reimplement + * std::char_traits if we wanted to use it with our constexpr basic_string_view. + */ +template +class basic_string_view final { + public: + using value_type = CharT; + using pointer = CharT*; + using const_pointer = const CharT*; + using reference = CharT&; + using const_reference = const CharT&; + using const_iterator = const CharT*; + using iterator = const_iterator; + using const_reverse_iterator = c10::reverse_iterator; + using reverse_iterator = const_reverse_iterator; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + static constexpr size_type npos = size_type(-1); + + constexpr basic_string_view() noexcept : begin_(nullptr), size_(0) {} + + explicit constexpr basic_string_view(const_pointer str, size_type count) + : begin_(str), size_(count) {} + + /* implicit */ constexpr basic_string_view(const_pointer str) + : basic_string_view(str, strlen_(str)) {} + + /* implicit */ basic_string_view(const ::std::basic_string& str) + : basic_string_view(str.data(), str.size()) {} + + constexpr basic_string_view(const basic_string_view&) noexcept = default; + + AT_CPP14_CONSTEXPR basic_string_view& operator=( + const basic_string_view& rhs) noexcept { + begin_ = rhs.begin_; + size_ = rhs.size_; + return *this; + } + + explicit operator ::std::basic_string() const { + return ::std::basic_string(data(), size()); + } + + constexpr const_iterator begin() const noexcept { + return cbegin(); + } + + constexpr const_iterator cbegin() const noexcept { + return begin_; + } + + constexpr const_iterator end() const noexcept { + return cend(); + } + + constexpr const_iterator cend() const noexcept { + return begin_ + size_; + } + + constexpr const_reverse_iterator rbegin() const noexcept { + return crbegin(); + } + + constexpr const_reverse_iterator crbegin() const noexcept { + return const_reverse_iterator(this->end()); + } + + constexpr const_reverse_iterator rend() const noexcept { + return crend(); + } + + constexpr const_reverse_iterator crend() const noexcept { + return const_reverse_iterator(this->begin()); + } + + friend constexpr const_iterator begin(basic_string_view sv) noexcept { + return sv.begin(); + } + + friend constexpr const_iterator end(basic_string_view sv) noexcept { + return sv.end(); + } + + constexpr const_reference operator[](size_type pos) const { + return at(pos); + } + + constexpr const_reference at(size_type pos) const { +#if !defined( \ + __CUDA_ARCH__) // CUDA doesn't like std::out_of_range in device code + return C10_UNLIKELY(pos >= size_) + ? (throw std::out_of_range( + "string_view::operator[] or string_view::at() out of range. Index: " + + std::to_string(pos) + ", size: " + std::to_string(size())), + at_(0)) + : at_(pos); +#else + return at_(pos); +#endif + } + + constexpr const_reference front() const { + return *begin_; + } + + constexpr const_reference back() const { + return *(begin_ + size_ - 1); + } + + constexpr const_pointer data() const noexcept { + return begin_; + } + + constexpr size_type size() const noexcept { + return size_; + } + + constexpr size_type length() const noexcept { + return size(); + } + + constexpr size_type max_size() const noexcept { + return std::numeric_limits::max(); + } + + C10_NODISCARD constexpr bool empty() const noexcept { + return size() == 0; + } + + CONSTEXPR_EXCEPT_GCC5 void remove_prefix(size_type n) { + if (n > size()) { + throw std::out_of_range( + "basic_string_view::remove_prefix: out of range. PrefixLength: " + + c10::guts::to_string(n) + ", size: " + c10::guts::to_string(size())); + } + begin_ += n; + size_ -= n; + } + + CONSTEXPR_EXCEPT_GCC5 void remove_suffix(size_type n) { + if (n > size()) { + throw std::out_of_range( + "basic_string_view::remove_suffix: out of range. SuffixLength: " + + c10::guts::to_string(n) + ", size: " + c10::guts::to_string(size())); + } + size_ -= n; + } + + CONSTEXPR_EXCEPT_GCC5 void swap(basic_string_view& sv) noexcept { + auto tmp = *this; + *this = sv; + sv = tmp; + } + + size_type copy(pointer dest, size_type count, size_type pos = 0) const { + if (pos > size_) { + throw std::out_of_range( + "basic_string_view::copy: out of range. Index: " + + c10::guts::to_string(pos) + + ", size: " + c10::guts::to_string(size())); + } + size_type copy_length = c10::guts::min(count, size_ - pos); + for (auto iter = begin() + pos, end = iter + copy_length; iter != end;) { + *(dest++) = *(iter++); + } + return copy_length; + } + + constexpr basic_string_view substr(size_type pos = 0, size_type count = npos) + const { +#if !defined( \ + __CUDA_ARCH__) // CUDA doesn't like std::out_of_range in device code + return (pos > size_) + ? (throw std::out_of_range( + "basic_string_view::substr parameter out of bounds. Index: " + + std::to_string(pos) + ", size: " + std::to_string(size())), + substr_()) + : substr_(pos, count); +#else + return substr_(pos, count); +#endif + } + + constexpr int compare(basic_string_view rhs) const noexcept { +#if __cpp_constexpr >= 201304 + // if we are in C++14, write it iteratively. This is faster. + for (size_t i = 0, end = c10::guts::min(size(), rhs.size()); i < end; ++i) { + if (at_(i) < rhs.at_(i)) { + return -1; + } else if (at_(i) > rhs.at_(i)) { + return 1; + } + } + if (size() < rhs.size()) { + return -1; + } else if (size() > rhs.size()) { + return 1; + } + return 0; +#else + // if we are in C++11, we need to do it recursively because of constexpr + // restrictions. + return (size() == 0 && rhs.size() == 0) ? 0 + : (size() == 0) ? -1 + : (rhs.size() == 0) + ? 1 + : (front() < rhs.front()) ? -1 + : (front() > rhs.front()) + ? 1 + : substr_(1).compare(rhs.substr_(1)); +#endif + } + + constexpr int compare(size_type pos1, size_type count1, basic_string_view v) + const { + return substr(pos1, count1).compare(v); + } + + constexpr int compare( + size_type pos1, + size_type count1, + basic_string_view v, + size_type pos2, + size_type count2) const { + return substr(pos1, count1).compare(v.substr(pos2, count2)); + } + + constexpr int compare(const_pointer s) const { + return compare(basic_string_view(s)); + } + + constexpr int compare(size_type pos1, size_type count1, const_pointer s) + const { + return substr(pos1, count1).compare(basic_string_view(s)); + } + + constexpr int compare( + size_type pos1, + size_type count1, + const_pointer s, + size_type count2) const { + return substr(pos1, count1).compare(basic_string_view(s, count2)); + } + + friend constexpr bool operator==( + basic_string_view lhs, + basic_string_view rhs) noexcept { + return lhs.equals_(rhs); + } + + friend constexpr bool operator!=( + basic_string_view lhs, + basic_string_view rhs) noexcept { + return !(lhs == rhs); + } + + friend constexpr bool operator<( + basic_string_view lhs, + basic_string_view rhs) noexcept { + return lhs.compare(rhs) < 0; + } + + friend constexpr bool operator>=( + basic_string_view lhs, + basic_string_view rhs) noexcept { + return !(lhs < rhs); + } + + friend constexpr bool operator>( + basic_string_view lhs, + basic_string_view rhs) noexcept { + return rhs < lhs; + } + + friend constexpr bool operator<=( + basic_string_view lhs, + basic_string_view rhs) noexcept { + return !(lhs > rhs); + } + + constexpr bool starts_with(basic_string_view prefix) const noexcept { + return (prefix.size() > size()) ? false + : prefix.equals_(substr_(0, prefix.size())); + } + + constexpr bool starts_with(CharT prefix) const noexcept { + return !empty() && prefix == front(); + } + + constexpr bool starts_with(const_pointer prefix) const { + return starts_with(basic_string_view(prefix)); + } + + constexpr bool ends_with(basic_string_view suffix) const noexcept { + return (suffix.size() > size()) + ? false + : suffix.equals_(substr_(size() - suffix.size(), suffix.size())); + } + + constexpr bool ends_with(CharT suffix) const noexcept { + return !empty() && suffix == back(); + } + + constexpr bool ends_with(const_pointer suffix) const { + return ends_with(basic_string_view(suffix)); + } + + constexpr size_type find(basic_string_view v, size_type pos = 0) const + noexcept { +#if __cpp_constexpr >= 201304 + // if we are in C++14, write it iteratively. This is faster. + if (v.size() == 0) { + return pos <= size() ? pos : npos; + } + + if (pos + v.size() <= size()) { + for (size_type cur = pos, end = size() - v.size(); cur <= end; ++cur) { + if (v.at_(0) == at_(cur) && + v.substr_(1).equals_(substr_(cur + 1, v.size() - 1))) { + return cur; + } + } + } + return npos; +#else + // if we are in C++11, we need to do it recursively because of constexpr + // restrictions. + return (v.size() == 0) ? (pos <= size() ? pos : npos) + : (pos + v.size() > size()) + ? npos + : (v.at_(0) == at_(pos) && + v.substr_(1).equals_(substr_(pos + 1, v.size() - 1))) + ? pos + : find(v, pos + 1); +#endif + } + + constexpr size_type find(CharT ch, size_type pos = 0) const noexcept { + return find_first_if_(pos, charIsEqual_{ch}); + } + + constexpr size_type find(const_pointer s, size_type pos, size_type count) + const { + return find(basic_string_view(s, count), pos); + } + + constexpr size_type find(const_pointer s, size_type pos = 0) const { + return find(basic_string_view(s), pos); + } + + constexpr size_type rfind(basic_string_view v, size_type pos = npos) const + noexcept { +#if __cpp_constexpr >= 201304 + // if we are in C++14, write it iteratively. This is faster. + if (v.size() == 0) { + return pos <= size() ? pos : size(); + } + + if (v.size() <= size()) { + pos = c10::guts::min(size() - v.size(), pos); + do { + if (v.at_(0) == at_(pos) && + v.substr_(1).equals_(substr_(pos + 1, v.size() - 1))) { + return pos; + } + } while (pos-- > 0); + } + return npos; +#else + // if we are in C++11, we need to do it recursively because of constexpr + // restrictions. + return (v.size() == 0) ? (pos <= size() ? pos : size()) + : (v.size() > size()) ? npos + : (size() - v.size() < pos) + ? rfind(v, size() - v.size()) + : (v.at_(0) == at_(pos) && + v.substr_(1).equals_(substr_(pos + 1, v.size() - 1))) + ? pos + : (pos == 0) ? npos : rfind(v, pos - 1); +#endif + } + + constexpr size_type rfind(CharT ch, size_type pos = npos) const noexcept { + return find_last_if_(pos, charIsEqual_{ch}); + } + + constexpr size_type rfind(const_pointer s, size_type pos, size_type count) + const { + return rfind(basic_string_view(s, count), pos); + } + + constexpr size_type rfind(const_pointer s, size_type pos = npos) const { + return rfind(basic_string_view(s), pos); + } + + constexpr size_type find_first_of(basic_string_view v, size_type pos = 0) + const noexcept { + return find_first_if_(pos, stringViewContainsChar_{v}); + } + + constexpr size_type find_first_of(CharT ch, size_type pos = 0) const + noexcept { + return find_first_if_(pos, charIsEqual_{ch}); + } + + constexpr size_type find_first_of( + const_pointer s, + size_type pos, + size_type count) const { + return find_first_of(basic_string_view(s, count), pos); + } + + constexpr size_type find_first_of(const_pointer s, size_type pos = 0) const { + return find_first_of(basic_string_view(s), pos); + } + + constexpr size_type find_last_of(basic_string_view v, size_type pos = npos) + const noexcept { + return find_last_if_(pos, stringViewContainsChar_{v}); + } + + constexpr size_type find_last_of(CharT ch, size_type pos = npos) const + noexcept { + return find_last_if_(pos, charIsEqual_{ch}); + } + + constexpr size_type find_last_of( + const_pointer s, + size_type pos, + size_type count) const { + return find_last_of(basic_string_view(s, count), pos); + } + + constexpr size_type find_last_of(const_pointer s, size_type pos = npos) + const { + return find_last_of(basic_string_view(s), pos); + } + + constexpr size_type find_first_not_of(basic_string_view v, size_type pos = 0) + const noexcept { + return find_first_if_(pos, stringViewDoesNotContainChar_{v}); + } + + constexpr size_type find_first_not_of(CharT ch, size_type pos = 0) const + noexcept { + return find_first_if_(pos, charIsNotEqual_{ch}); + } + + constexpr size_type find_first_not_of( + const_pointer s, + size_type pos, + size_type count) const { + return find_first_not_of(basic_string_view(s, count), pos); + } + + constexpr size_type find_first_not_of(const_pointer s, size_type pos = 0) + const { + return find_first_not_of(basic_string_view(s), pos); + } + + constexpr size_type find_last_not_of( + basic_string_view v, + size_type pos = npos) const noexcept { + return find_last_if_(pos, stringViewDoesNotContainChar_{v}); + } + + constexpr size_type find_last_not_of(CharT ch, size_type pos = npos) const + noexcept { + return find_last_if_(pos, charIsNotEqual_{ch}); + } + + constexpr size_type find_last_not_of( + const_pointer s, + size_type pos, + size_type count) const { + return find_last_not_of(basic_string_view(s, count), pos); + } + + constexpr size_type find_last_not_of(const_pointer s, size_type pos = npos) + const { + return find_last_not_of(basic_string_view(s), pos); + } + + private: + static constexpr size_type strlen_(const_pointer str) noexcept { +#if __cpp_constexpr >= 201304 + // if we are in C++14, write it iteratively. This is faster. + const_pointer current = str; + while (*current != '\0') { + ++current; + } + return current - str; +#else + // if we are in C++11, we need to do it recursively because of constexpr + // restrictions. + return (*str == '\0') ? 0 : 1 + strlen_(str + 1); +#endif + } + + constexpr const_reference at_(size_type pos) const noexcept { + return *(begin_ + pos); + } + + constexpr basic_string_view substr_(size_type pos = 0, size_type count = npos) + const { + return basic_string_view{begin_ + pos, c10::guts::min(count, size() - pos)}; + } + + template + constexpr size_type find_first_if_(size_type pos, Condition&& condition) const + noexcept { +#if __cpp_constexpr >= 201304 + // if we are in C++14, write it iteratively. This is faster. + if (pos + 1 <= size()) { + for (size_type cur = pos; cur < size(); ++cur) { + if (condition(at_(cur))) { + return cur; + } + } + } + return npos; +#else + // if we are in C++11, we need to do it recursively because of constexpr + // restrictions. + return (pos + 1 > size()) ? npos + : condition(at_(pos)) + ? pos + : find_first_if_(pos + 1, std::forward(condition)); +#endif + } + + template + constexpr size_type find_last_if_(size_type pos, Condition&& condition) const + noexcept { +#if __cpp_constexpr >= 201304 + // if we are in C++14, write it iteratively. This is faster. + if (size() > 0) { + pos = c10::guts::min(size() - 1, pos); + do { + if (condition(at_(pos))) { + return pos; + } + } while (pos-- > 0); + } + return npos; +#else + // if we are in C++11, we need to do it recursively because of constexpr + // restrictions. + return (size() == 0) ? npos + : (pos >= size()) + ? find_last_if_(size() - 1, std::forward(condition)) + : condition(at_(pos)) + ? pos + : (pos == 0) ? npos + : find_last_if_( + pos - 1, std::forward(condition)); +#endif + } + + constexpr bool equals_(basic_string_view rhs) const { +// We don't use string_view::compare() here but implement it manually because +// only looking at equality allows for more optimized code. +#if __cpp_constexpr >= 201304 + // if we are in C++14, write it iteratively. This is faster. + if (size() != rhs.size()) { + return false; + } + // Yes, memcmp would be laster than this loop, but memcmp isn't constexpr + // and I didn't feel like implementing a constexpr memcmp variant. + // TODO At some point this should probably be done, including tricks + // like comparing one machine word instead of a byte per iteration. + for (typename basic_string_view::size_type pos = 0; pos < size(); + ++pos) { + if (at_(pos) != rhs.at_(pos)) { + return false; + } + } + return true; +#else + // if we are in C++11, we need to do it recursively because of constexpr + // restrictions. + return (size() != rhs.size()) ? false + : (size() == 0) + ? true + : (front() != rhs.front()) ? false + : (substr_(1).equals_(rhs.substr_(1))); +#endif + } + + struct charIsEqual_ final { + CharT expected; + constexpr bool operator()(CharT actual) const noexcept { + return expected == actual; + } + }; + + struct charIsNotEqual_ final { + CharT expected; + constexpr bool operator()(CharT actual) const noexcept { + return expected != actual; + } + }; + + struct stringViewContainsChar_ final { + basic_string_view expected; + constexpr bool operator()(CharT ch) const noexcept { + return npos != expected.find(ch); + } + }; + + struct stringViewDoesNotContainChar_ final { + basic_string_view expected; + constexpr bool operator()(CharT ch) const noexcept { + return npos == expected.find(ch); + } + }; + + const_pointer begin_; + size_type size_; +}; + +template +inline std::basic_ostream& operator<<( + std::basic_ostream& stream, + basic_string_view sv) { + // The rules for operator<< are quite complex, but std::string has the same. + // Let's just rely on the std::string implementation. This might be a bit + // slower, but I don't think performance matters here. + return stream << ::std::basic_string(sv); +} + +template +CONSTEXPR_EXCEPT_GCC5 inline void swap( + basic_string_view& lhs, + basic_string_view& rhs) { + lhs.swap(rhs); +} + +using string_view = basic_string_view; + +} // namespace c10 + +namespace std { +template +struct hash<::c10::basic_string_view> { + size_t operator()(::c10::basic_string_view x) const { + // The standard says that std""string_view hashing must do the same as + // std::string hashing but leaves the details of std::string hashing + // up to the implementer. So, to be conformant, we need to have the same + // behavior as the implementer-defined std::string hasher of the STL + // we're built against. Let's just call it. This is probably slow + // but the only way to be conformant. + return std::hash<::std::basic_string>()( + ::std::basic_string(x)); + } +}; +} // namespace std