[libc-commits] [libc] a7eaec7 - [libc] Change cpp::string_view into cpp::basic_string_view<CharT> (#203355)

via libc-commits libc-commits at lists.llvm.org
Fri Jun 26 04:14:13 PDT 2026


Author: Alex Strelnikov
Date: 2026-06-26T11:14:08Z
New Revision: a7eaec767388a4ba00897156762f0387afcf15a5

URL: https://github.com/llvm/llvm-project/commit/a7eaec767388a4ba00897156762f0387afcf15a5
DIFF: https://github.com/llvm/llvm-project/commit/a7eaec767388a4ba00897156762f0387afcf15a5.diff

LOG: [libc] Change cpp::string_view into cpp::basic_string_view<CharT> (#203355)

This will allow some of the types in src/stdio/printf_core/ to be
templated on character type for the implementation of `swprintf`.

Added: 
    

Modified: 
    libc/src/__support/CPP/string_view.h
    libc/src/__support/CPP/type_traits/is_integral.h
    libc/test/UnitTest/LibcTest.cpp
    libc/test/UnitTest/LibcTest.h
    libc/test/src/__support/CPP/CMakeLists.txt
    libc/test/src/__support/CPP/stringview_test.cpp

Removed: 
    


################################################################################
diff  --git a/libc/src/__support/CPP/string_view.h b/libc/src/__support/CPP/string_view.h
index 7b98b7e5fb6c8..68056f753c314 100644
--- a/libc/src/__support/CPP/string_view.h
+++ b/libc/src/__support/CPP/string_view.h
@@ -18,48 +18,52 @@
 namespace LIBC_NAMESPACE_DECL {
 namespace cpp {
 
-// This is very simple alternate of the std::string_view class. There is no
-// bounds check performed in any of the methods. The callers are expected to
-// do the checks before invoking the methods.
+template <typename CharT> class basic_string_view;
+
+using string_view = basic_string_view<char>;
+using wstring_view = basic_string_view<wchar_t>;
+
+// This is a very simple alternate of the std::basic_string_view class template.
+// There is no bounds check performed in any of the methods. The callers are
+// expected to do the checks before invoking the methods.
 //
 // This class will be extended as needed in future.
-class string_view {
+template <typename CharT> class basic_string_view {
 private:
-  const char *Data;
+  const CharT *Data;
   size_t Len;
 
   LIBC_INLINE static constexpr size_t min(size_t A, size_t B) {
     return A <= B ? A : B;
   }
 
-  LIBC_INLINE static constexpr int
-  compareMemory(const char *Lhs, const char *Rhs, size_t Length) {
+  LIBC_INLINE static constexpr int compareN(const CharT *Lhs, const CharT *Rhs,
+                                            size_t Length) {
     for (size_t i = 0; i < Length; ++i)
-      if (int Diff = (int)Lhs[i] - (int)Rhs[i])
-        return Diff;
+      if (Lhs[i] != Rhs[i])
+        return Lhs[i] < Rhs[i] ? -1 : 1;
     return 0;
   }
 
-  LIBC_INLINE static constexpr size_t length(const char *Str) {
-    for (const char *End = Str;; ++End)
-      if (*End == '\0')
+  LIBC_INLINE static constexpr size_t length(const CharT *Str) {
+    for (const CharT *End = Str;; ++End)
+      if (*End == CharT{0})
         return static_cast<size_t>(End - Str);
   }
 
-  LIBC_INLINE constexpr bool equals(string_view Other) const {
-    return (Len == Other.Len &&
-            compareMemory(Data, Other.Data, Other.Len) == 0);
+  LIBC_INLINE constexpr bool equals(basic_string_view Other) const {
+    return (Len == Other.Len && compareN(Data, Other.Data, Other.Len) == 0);
   }
 
 public:
-  using value_type = char;
+  using value_type = CharT;
   using size_type = size_t;
   using 
diff erence_type = ptr
diff _t;
-  using pointer = char *;
-  using const_pointer = const char *;
-  using reference = char &;
-  using const_reference = const char &;
-  using const_iterator = char *;
+  using pointer = CharT *;
+  using const_pointer = const CharT *;
+  using reference = CharT &;
+  using const_reference = const CharT &;
+  using const_iterator = CharT *;
   using iterator = const_iterator;
 
   // special value equal to the maximum value representable by the type
@@ -67,68 +71,68 @@ class string_view {
   LIBC_INLINE_VAR static constexpr size_t npos =
       cpp::numeric_limits<size_t>::max();
 
-  LIBC_INLINE constexpr string_view() : Data(nullptr), Len(0) {}
+  LIBC_INLINE constexpr basic_string_view() : Data(nullptr), Len(0) {}
 
   // Assumes Str is a null-terminated string. The length of the string does
   // not include the terminating null character.
   // Preconditions: [Str, Str + ​length(Str)) is a valid range.
-  LIBC_INLINE constexpr string_view(const char *Str)
+  LIBC_INLINE constexpr basic_string_view(const CharT *Str)
       : Data(Str), Len(length(Str)) {}
 
   // Preconditions: [Str, Str + N) is a valid range.
-  LIBC_INLINE constexpr string_view(const char *Str, size_t N)
+  LIBC_INLINE constexpr basic_string_view(const CharT *Str, size_t N)
       : Data(Str), Len(N) {}
 
-  LIBC_INLINE constexpr const char *data() const { return Data; }
+  LIBC_INLINE constexpr const CharT *data() const { return Data; }
 
-  // Returns the size of the string_view.
+  // Returns the size of the basic_string_view.
   LIBC_INLINE constexpr size_t size() const { return Len; }
 
-  // Returns whether the string_view is empty.
+  // Returns whether the basic_string_view is empty.
   LIBC_INLINE constexpr bool empty() const { return Len == 0; }
 
   // Returns an iterator to the first character of the view.
-  LIBC_INLINE constexpr const char *begin() const { return Data; }
+  LIBC_INLINE constexpr const CharT *begin() const { return Data; }
 
   // Returns an iterator to the character following the last character of the
   // view.
-  LIBC_INLINE constexpr const char *end() const { return Data + Len; }
+  LIBC_INLINE constexpr const CharT *end() const { return Data + Len; }
 
   // Returns a const reference to the character at specified location pos.
   // No bounds checking is performed: the behavior is undefined if pos >=
   // size().
-  LIBC_INLINE constexpr const char &operator[](size_t Index) const {
+  LIBC_INLINE constexpr const CharT &operator[](size_t Index) const {
     return Data[Index];
   }
 
   /// compare - Compare two strings; the result is -1, 0, or 1 if this string
   /// is lexicographically less than, equal to, or greater than the \p Other.
-  LIBC_INLINE constexpr int compare(string_view Other) const {
+  LIBC_INLINE constexpr int compare(basic_string_view Other) const {
     // Check the prefix for a mismatch.
-    if (int Res = compareMemory(Data, Other.Data, min(Len, Other.Len)))
-      return Res < 0 ? -1 : 1;
+    if (int Res = compareN(Data, Other.Data, min(Len, Other.Len)))
+      return Res;
     // Otherwise the prefixes match, so we only need to check the lengths.
     if (Len == Other.Len)
       return 0;
     return Len < Other.Len ? -1 : 1;
   }
 
-  LIBC_INLINE constexpr bool operator==(string_view Other) const {
+  LIBC_INLINE constexpr bool operator==(basic_string_view Other) const {
     return equals(Other);
   }
-  LIBC_INLINE constexpr bool operator!=(string_view Other) const {
+  LIBC_INLINE constexpr bool operator!=(basic_string_view Other) const {
     return !(*this == Other);
   }
-  LIBC_INLINE constexpr bool operator<(string_view Other) const {
+  LIBC_INLINE constexpr bool operator<(basic_string_view Other) const {
     return compare(Other) == -1;
   }
-  LIBC_INLINE constexpr bool operator<=(string_view Other) const {
+  LIBC_INLINE constexpr bool operator<=(basic_string_view Other) const {
     return compare(Other) != 1;
   }
-  LIBC_INLINE constexpr bool operator>(string_view Other) const {
+  LIBC_INLINE constexpr bool operator>(basic_string_view Other) const {
     return compare(Other) == 1;
   }
-  LIBC_INLINE constexpr bool operator>=(string_view Other) const {
+  LIBC_INLINE constexpr bool operator>=(basic_string_view Other) const {
     return compare(Other) != -1;
   }
 
@@ -144,25 +148,24 @@ class string_view {
   LIBC_INLINE constexpr void remove_suffix(size_t N) { Len -= N; }
 
   // Check if this string starts with the given Prefix.
-  LIBC_INLINE constexpr bool starts_with(string_view Prefix) const {
-    return Len >= Prefix.Len &&
-           compareMemory(Data, Prefix.Data, Prefix.Len) == 0;
+  LIBC_INLINE constexpr bool starts_with(basic_string_view Prefix) const {
+    return Len >= Prefix.Len && compareN(Data, Prefix.Data, Prefix.Len) == 0;
   }
 
   // Check if this string starts with the given Prefix.
-  LIBC_INLINE constexpr bool starts_with(const char Prefix) const {
+  LIBC_INLINE constexpr bool starts_with(const CharT Prefix) const {
     return !empty() && front() == Prefix;
   }
 
   // Check if this string ends with the given Prefix.
-  LIBC_INLINE constexpr bool ends_with(const char Suffix) const {
+  LIBC_INLINE constexpr bool ends_with(const CharT Suffix) const {
     return !empty() && back() == Suffix;
   }
 
   // Check if this string ends with the given Suffix.
-  LIBC_INLINE constexpr bool ends_with(string_view Suffix) const {
+  LIBC_INLINE constexpr bool ends_with(basic_string_view Suffix) const {
     return Len >= Suffix.Len &&
-           compareMemory(end() - Suffix.Len, Suffix.Data, Suffix.Len) == 0;
+           compareN(end() - Suffix.Len, Suffix.Data, Suffix.Len) == 0;
   }
 
   // Return a reference to the substring from [Start, Start + N).
@@ -174,20 +177,20 @@ class string_view {
   // N The number of characters to included in the substring. If N exceeds the
   // number of characters remaining in the string, the string suffix (starting
   // with Start) will be returned.
-  LIBC_INLINE constexpr string_view substr(size_t Start,
-                                           size_t N = npos) const {
+  LIBC_INLINE constexpr basic_string_view substr(size_t Start,
+                                                 size_t N = npos) const {
     Start = min(Start, Len);
-    return string_view(Data + Start, min(N, Len - Start));
+    return basic_string_view(Data + Start, min(N, Len - Start));
   }
 
   // front - Get the first character in the string.
-  LIBC_INLINE constexpr char front() const { return Data[0]; }
+  LIBC_INLINE constexpr CharT front() const { return Data[0]; }
 
   // back - Get the last character in the string.
-  LIBC_INLINE constexpr char back() const { return Data[Len - 1]; }
+  LIBC_INLINE constexpr CharT back() const { return Data[Len - 1]; }
 
   // Finds the first occurence of c in this view, starting at position From.
-  LIBC_INLINE constexpr size_t find_first_of(const char c,
+  LIBC_INLINE constexpr size_t find_first_of(const CharT c,
                                              size_t From = 0) const {
     for (size_t Pos = From; Pos < size(); ++Pos)
       if ((*this)[Pos] == c)
@@ -196,7 +199,7 @@ class string_view {
   }
 
   // Finds the last occurence of c in this view, ending at position End.
-  LIBC_INLINE constexpr size_t find_last_of(const char c,
+  LIBC_INLINE constexpr size_t find_last_of(const CharT c,
                                             size_t End = npos) const {
     End = End >= size() ? size() : End + 1;
     for (; End > 0; --End)
@@ -216,7 +219,7 @@ class string_view {
 
   // Finds the first character not equal to c in this view, starting at
   // position From.
-  LIBC_INLINE constexpr size_t find_first_not_of(const char c,
+  LIBC_INLINE constexpr size_t find_first_not_of(const CharT c,
                                                  size_t From = 0) const {
     for (size_t Pos = From; Pos < size(); ++Pos)
       if ((*this)[Pos] != c)
@@ -225,7 +228,7 @@ class string_view {
   }
 
   // Check if this view contains the given character.
-  LIBC_INLINE constexpr bool contains(char c) const {
+  LIBC_INLINE constexpr bool contains(CharT c) const {
     return find_first_of(c) != npos;
   }
 };

diff  --git a/libc/src/__support/CPP/type_traits/is_integral.h b/libc/src/__support/CPP/type_traits/is_integral.h
index 09047cb00bf75..c02bfcd50fea6 100644
--- a/libc/src/__support/CPP/type_traits/is_integral.h
+++ b/libc/src/__support/CPP/type_traits/is_integral.h
@@ -34,7 +34,7 @@ template <typename T> struct is_integral {
 #ifdef __cpp_char8_t
                               char8_t,
 #endif
-                              char16_t, char32_t, char, signed char,
+                              char16_t, char32_t, wchar_t, char, signed char,
                               unsigned char, short, unsigned short, int,
                               unsigned int, long, unsigned long, long long,
                               unsigned long long, bool>();

diff  --git a/libc/test/UnitTest/LibcTest.cpp b/libc/test/UnitTest/LibcTest.cpp
index fec45982f3e63..b03ceb6c7c77d 100644
--- a/libc/test/UnitTest/LibcTest.cpp
+++ b/libc/test/UnitTest/LibcTest.cpp
@@ -70,6 +70,22 @@ cpp::enable_if_t<cpp::is_fixed_point_v<T>, cpp::string> describeValue(T Value) {
 cpp::string_view describeValue(const cpp::string &Value) { return Value; }
 cpp::string_view describeValue(cpp::string_view Value) { return Value; }
 
+cpp::string describeValue(cpp::wstring_view Value) {
+  // TODO: Print `Value` as UTF-8 once `StringConverter` supports `wchar_t`.
+  if (Value.empty())
+    return "{}";
+
+  cpp::string S;
+  S += '{';
+  for (const wchar_t *Iter = Value.begin(); Iter + 1 != Value.end(); ++Iter) {
+    S += cpp::to_string(*Iter);
+    S += ',';
+  }
+  S += cpp::to_string(Value.back());
+  S += '}';
+  return S;
+}
+
 template <typename ValType>
 bool test(RunContext *Ctx, TestCond Cond, ValType LHS, ValType RHS,
           const char *LHSStr, const char *RHSStr, Location Loc) {
@@ -217,6 +233,8 @@ namespace internal {
                            TYPE RHS, const char *LHSStr, const char *RHSStr,   \
                            Location Loc)
 
+TEST_SPECIALIZATION(wchar_t);
+
 TEST_SPECIALIZATION(char);
 TEST_SPECIALIZATION(short);
 TEST_SPECIALIZATION(int);
@@ -249,6 +267,7 @@ TEST_SPECIALIZATION(LIBC_NAMESPACE::UInt<256>);
 TEST_SPECIALIZATION(LIBC_NAMESPACE::UInt<320>);
 
 TEST_SPECIALIZATION(LIBC_NAMESPACE::cpp::string_view);
+TEST_SPECIALIZATION(LIBC_NAMESPACE::cpp::wstring_view);
 TEST_SPECIALIZATION(LIBC_NAMESPACE::cpp::string);
 
 #ifdef LIBC_COMPILER_HAS_FIXED_POINT

diff  --git a/libc/test/UnitTest/LibcTest.h b/libc/test/UnitTest/LibcTest.h
index 133c198d42f15..65884b56f1dde 100644
--- a/libc/test/UnitTest/LibcTest.h
+++ b/libc/test/UnitTest/LibcTest.h
@@ -180,6 +180,15 @@ class Test {
     return internal::test(Ctx, Cond, LHS, RHS, LHSStr, RHSStr, Loc);
   }
 
+  template <
+      typename ValType,
+      cpp::enable_if_t<
+          cpp::is_same_v<ValType, LIBC_NAMESPACE::cpp::wstring_view>, int> = 0>
+  bool test(TestCond Cond, ValType LHS, ValType RHS, const char *LHSStr,
+            const char *RHSStr, internal::Location Loc) {
+    return internal::test(Ctx, Cond, LHS, RHS, LHSStr, RHSStr, Loc);
+  }
+
   template <typename ValType,
             cpp::enable_if_t<
                 cpp::is_same_v<ValType, LIBC_NAMESPACE::cpp::string>, int> = 0>

diff  --git a/libc/test/src/__support/CPP/CMakeLists.txt b/libc/test/src/__support/CPP/CMakeLists.txt
index 1d47455dcd31f..9c09684be192d 100644
--- a/libc/test/src/__support/CPP/CMakeLists.txt
+++ b/libc/test/src/__support/CPP/CMakeLists.txt
@@ -61,6 +61,8 @@ add_libc_test(
     stringview_test.cpp
   DEPENDS
     libc.src.__support.CPP.string_view
+    libc.src.__support.CPP.type_traits
+    libc.src.string.memory_utils.inline_memcpy
 )
 
 add_libc_test(

diff  --git a/libc/test/src/__support/CPP/stringview_test.cpp b/libc/test/src/__support/CPP/stringview_test.cpp
index c9348243745a7..d8c2e03a4e9b2 100644
--- a/libc/test/src/__support/CPP/stringview_test.cpp
+++ b/libc/test/src/__support/CPP/stringview_test.cpp
@@ -7,279 +7,332 @@
 //===----------------------------------------------------------------------===//
 
 #include "src/__support/CPP/string_view.h"
+#include "src/__support/CPP/type_traits.h"
+#include "src/string/memory_utils/inline_memcpy.h"
 #include "test/UnitTest/Test.h"
 
-using LIBC_NAMESPACE::cpp::string_view;
+using TestCharTypes = LIBC_NAMESPACE::testing::TypeList<char, wchar_t>;
 
-TEST(LlvmLibcStringViewTest, InitializeCheck) {
-  string_view v;
-  ASSERT_EQ(v.size(), size_t(0));
-  ASSERT_TRUE(v.data() == nullptr);
+template <typename CharT>
+const CharT *chooseLiteral(const char *CharStr, const wchar_t *WCharStr) {
+  if constexpr (LIBC_NAMESPACE::cpp::is_same_v<CharT, char>)
+    return CharStr;
+  else {
+    static_assert(LIBC_NAMESPACE::cpp::is_same_v<CharT, wchar_t>);
+    return WCharStr;
+  }
+}
+
+template <typename CharT>
+CharT chooseLiteral(char CharValue, wchar_t WCharValue) {
+  if constexpr (LIBC_NAMESPACE::cpp::is_same_v<CharT, char>)
+    return CharValue;
+  else {
+    static_assert(LIBC_NAMESPACE::cpp::is_same_v<CharT, wchar_t>);
+    return WCharValue;
+  }
+}
+
+#define ENCODED(CharT, S) chooseLiteral<CharT>(S, L##S)
 
-  v = string_view("");
-  ASSERT_EQ(v.size(), size_t(0));
-  ASSERT_TRUE(v.data() != nullptr);
+TYPED_TEST(LlvmLibcStringViewTest, InitializeCheck, TestCharTypes) {
+  using CharT = ParamType;
+  using StringView = LIBC_NAMESPACE::cpp::basic_string_view<CharT>;
 
-  v = string_view("abc", 0);
-  ASSERT_EQ(v.size(), size_t(0));
-  ASSERT_TRUE(v.data() != nullptr);
+  StringView S;
+  ASSERT_EQ(S.size(), size_t(0));
+  ASSERT_TRUE(S.data() == nullptr);
 
-  v = string_view("123456789");
-  ASSERT_EQ(v.size(), size_t(9));
+  S = StringView(ENCODED(CharT, ""));
+  ASSERT_EQ(S.size(), size_t(0));
+  ASSERT_TRUE(S.data() != nullptr);
+
+  S = StringView(ENCODED(CharT, "abc"), 0);
+  ASSERT_EQ(S.size(), size_t(0));
+  ASSERT_TRUE(S.data() != nullptr);
+
+  S = StringView(ENCODED(CharT, "123456789"));
+  ASSERT_EQ(S.size(), size_t(9));
+
+  S = StringView(ENCODED(CharT, "123456789"), 5);
+  ASSERT_EQ(S.size(), size_t(5));
 }
 
-TEST(LlvmLibcStringViewTest, Equals) {
-  string_view v("abc");
-  ASSERT_EQ(v, string_view("abc"));
-  ASSERT_NE(v, string_view());
-  ASSERT_NE(v, string_view(""));
-  ASSERT_NE(v, string_view("123"));
-  ASSERT_NE(v, string_view("abd"));
-  ASSERT_NE(v, string_view("aaa"));
-  ASSERT_NE(v, string_view("abcde"));
+TYPED_TEST(LlvmLibcStringViewTest, Equals, TestCharTypes) {
+  using CharT = ParamType;
+  using StringView = LIBC_NAMESPACE::cpp::basic_string_view<CharT>;
+
+  StringView S(ENCODED(CharT, "abc"));
+  ASSERT_EQ(S, StringView(ENCODED(CharT, "abc")));
+  ASSERT_NE(S, StringView());
+  ASSERT_NE(S, StringView(ENCODED(CharT, "")));
+  ASSERT_NE(S, StringView(ENCODED(CharT, "123")));
+  ASSERT_NE(S, StringView(ENCODED(CharT, "abd")));
+  ASSERT_NE(S, StringView(ENCODED(CharT, "aaa")));
+  ASSERT_NE(S, StringView(ENCODED(CharT, "abcde")));
 }
 
-TEST(LlvmLibcStringViewTest, startsWith) {
-  string_view v("abc");
-  ASSERT_TRUE(v.starts_with('a'));
-  ASSERT_TRUE(v.starts_with(string_view("a")));
-  ASSERT_TRUE(v.starts_with(string_view("ab")));
-  ASSERT_TRUE(v.starts_with(string_view("abc")));
-  ASSERT_TRUE(v.starts_with(string_view()));
-  ASSERT_TRUE(v.starts_with(string_view("")));
-  ASSERT_FALSE(v.starts_with('1'));
-  ASSERT_FALSE(v.starts_with(string_view("123")));
-  ASSERT_FALSE(v.starts_with(string_view("abd")));
-  ASSERT_FALSE(v.starts_with(string_view("aaa")));
-  ASSERT_FALSE(v.starts_with(string_view("abcde")));
+TYPED_TEST(LlvmLibcStringViewTest, startsWith, TestCharTypes) {
+  using CharT = ParamType;
+  using StringView = LIBC_NAMESPACE::cpp::basic_string_view<CharT>;
+
+  StringView S(ENCODED(CharT, "abc"));
+  ASSERT_TRUE(S.starts_with(ENCODED(CharT, 'a')));
+  ASSERT_TRUE(S.starts_with(StringView(ENCODED(CharT, "a"))));
+  ASSERT_TRUE(S.starts_with(StringView(ENCODED(CharT, "ab"))));
+  ASSERT_TRUE(S.starts_with(StringView(ENCODED(CharT, "abc"))));
+  ASSERT_TRUE(S.starts_with(StringView()));
+  ASSERT_TRUE(S.starts_with(StringView(ENCODED(CharT, ""))));
+  ASSERT_FALSE(S.starts_with(ENCODED(CharT, '1')));
+  ASSERT_FALSE(S.starts_with(StringView(ENCODED(CharT, "123"))));
+  ASSERT_FALSE(S.starts_with(StringView(ENCODED(CharT, "abd"))));
+  ASSERT_FALSE(S.starts_with(StringView(ENCODED(CharT, "aaa"))));
+  ASSERT_FALSE(S.starts_with(StringView(ENCODED(CharT, "abcde"))));
 }
 
-TEST(LlvmLibcStringViewTest, endsWith) {
-  string_view v("abc");
-  ASSERT_TRUE(v.ends_with('c'));
-  ASSERT_TRUE(v.ends_with(string_view("c")));
-  ASSERT_TRUE(v.ends_with(string_view("bc")));
-  ASSERT_TRUE(v.ends_with(string_view("abc")));
-  ASSERT_TRUE(v.ends_with(string_view()));
-  ASSERT_TRUE(v.ends_with(string_view("")));
-  ASSERT_FALSE(v.ends_with('1'));
-  ASSERT_FALSE(v.ends_with(string_view("123")));
-  ASSERT_FALSE(v.ends_with(string_view("abd")));
-  ASSERT_FALSE(v.ends_with(string_view("aaa")));
-  ASSERT_FALSE(v.ends_with(string_view("abcde")));
+TYPED_TEST(LlvmLibcStringViewTest, endsWith, TestCharTypes) {
+  using CharT = ParamType;
+  using StringView = LIBC_NAMESPACE::cpp::basic_string_view<CharT>;
+
+  StringView S(ENCODED(CharT, "abc"));
+  ASSERT_TRUE(S.ends_with(ENCODED(CharT, 'c')));
+  ASSERT_TRUE(S.ends_with(StringView(ENCODED(CharT, "c"))));
+  ASSERT_TRUE(S.ends_with(StringView(ENCODED(CharT, "bc"))));
+  ASSERT_TRUE(S.ends_with(StringView(ENCODED(CharT, "abc"))));
+  ASSERT_TRUE(S.ends_with(StringView()));
+  ASSERT_TRUE(S.ends_with(StringView(ENCODED(CharT, ""))));
+  ASSERT_FALSE(S.ends_with(ENCODED(CharT, '1')));
+  ASSERT_FALSE(S.ends_with(StringView(ENCODED(CharT, "123"))));
+  ASSERT_FALSE(S.ends_with(StringView(ENCODED(CharT, "abd"))));
+  ASSERT_FALSE(S.ends_with(StringView(ENCODED(CharT, "aaa"))));
+  ASSERT_FALSE(S.ends_with(StringView(ENCODED(CharT, "abcde"))));
 }
 
-TEST(LlvmLibcStringViewTest, RemovePrefix) {
-  string_view a("123456789");
-  a.remove_prefix(0);
-  ASSERT_EQ(a.size(), size_t(9));
-  ASSERT_TRUE(a == "123456789");
+TYPED_TEST(LlvmLibcStringViewTest, RemovePrefix, TestCharTypes) {
+  using CharT = ParamType;
+  using StringView = LIBC_NAMESPACE::cpp::basic_string_view<CharT>;
+
+  StringView A(ENCODED(CharT, "123456789"));
+  A.remove_prefix(0);
+  ASSERT_EQ(A.size(), size_t(9));
+  ASSERT_TRUE(A == ENCODED(CharT, "123456789"));
 
-  string_view b("123456789");
-  b.remove_prefix(4);
-  ASSERT_EQ(b.size(), size_t(5));
-  ASSERT_TRUE(b == "56789");
+  StringView B(ENCODED(CharT, "123456789"));
+  B.remove_prefix(4);
+  ASSERT_EQ(B.size(), size_t(5));
+  ASSERT_TRUE(B == ENCODED(CharT, "56789"));
 
-  string_view c("123456789");
-  c.remove_prefix(9);
-  ASSERT_EQ(c.size(), size_t(0));
+  StringView C(ENCODED(CharT, "123456789"));
+  C.remove_prefix(9);
+  ASSERT_EQ(C.size(), size_t(0));
 }
 
-TEST(LlvmLibcStringViewTest, RemoveSuffix) {
-  string_view a("123456789");
-  a.remove_suffix(0);
-  ASSERT_EQ(a.size(), size_t(9));
-  ASSERT_TRUE(a == "123456789");
+TYPED_TEST(LlvmLibcStringViewTest, RemoveSuffix, TestCharTypes) {
+  using CharT = ParamType;
+  using StringView = LIBC_NAMESPACE::cpp::basic_string_view<CharT>;
 
-  string_view b("123456789");
-  b.remove_suffix(4);
-  ASSERT_EQ(b.size(), size_t(5));
-  ASSERT_TRUE(b == "12345");
+  StringView A(ENCODED(CharT, "123456789"));
+  A.remove_suffix(0);
+  ASSERT_EQ(A.size(), size_t(9));
+  ASSERT_TRUE(A == ENCODED(CharT, "123456789"));
 
-  string_view c("123456789");
-  c.remove_suffix(9);
-  ASSERT_EQ(c.size(), size_t(0));
+  StringView B(ENCODED(CharT, "123456789"));
+  B.remove_suffix(4);
+  ASSERT_EQ(B.size(), size_t(5));
+  ASSERT_TRUE(B == ENCODED(CharT, "12345"));
+
+  StringView C(ENCODED(CharT, "123456789"));
+  C.remove_suffix(9);
+  ASSERT_EQ(C.size(), size_t(0));
 }
 
-TEST(LlvmLibcStringViewTest, Observer) {
-  string_view ABC("abc");
+TYPED_TEST(LlvmLibcStringViewTest, Observer, TestCharTypes) {
+  using CharT = ParamType;
+  using StringView = LIBC_NAMESPACE::cpp::basic_string_view<CharT>;
+
+  StringView ABC(ENCODED(CharT, "abc"));
   ASSERT_EQ(ABC.size(), size_t(3));
   ASSERT_FALSE(ABC.empty());
-  ASSERT_EQ(ABC.front(), 'a');
-  ASSERT_EQ(ABC.back(), 'c');
+  ASSERT_EQ(ABC.front(), ENCODED(CharT, 'a'));
+  ASSERT_EQ(ABC.back(), ENCODED(CharT, 'c'));
+}
+
+TYPED_TEST(LlvmLibcStringViewTest, FindFirstOf, TestCharTypes) {
+  using CharT = ParamType;
+  using StringView = LIBC_NAMESPACE::cpp::basic_string_view<CharT>;
+
+  StringView Tmp(ENCODED(CharT, "abca"));
+  ASSERT_TRUE(Tmp.find_first_of(ENCODED(CharT, 'a')) == 0);
+  ASSERT_TRUE(Tmp.find_first_of(ENCODED(CharT, 'd')) == StringView::npos);
+  ASSERT_TRUE(Tmp.find_first_of(ENCODED(CharT, 'b')) == 1);
+  ASSERT_TRUE(Tmp.find_first_of(ENCODED(CharT, 'a'), 0) == 0);
+  ASSERT_TRUE(Tmp.find_first_of(ENCODED(CharT, 'b'), 1) == 1);
+  ASSERT_TRUE(Tmp.find_first_of(ENCODED(CharT, 'a'), 1) == 3);
+  ASSERT_TRUE(Tmp.find_first_of(ENCODED(CharT, 'a'), 42) == StringView::npos);
+  ASSERT_FALSE(Tmp.find_first_of(ENCODED(CharT, 'c')) == 1);
+  ASSERT_FALSE(Tmp.find_first_of(ENCODED(CharT, 'c'), 0) == 1);
+  ASSERT_FALSE(Tmp.find_first_of(ENCODED(CharT, 'c'), 1) == 1);
 }
 
-TEST(LlvmLibcStringViewTest, FindFirstOf) {
-  string_view Tmp("abca");
-  ASSERT_TRUE(Tmp.find_first_of('a') == 0);
-  ASSERT_TRUE(Tmp.find_first_of('d') == string_view::npos);
-  ASSERT_TRUE(Tmp.find_first_of('b') == 1);
-  ASSERT_TRUE(Tmp.find_first_of('a', 0) == 0);
-  ASSERT_TRUE(Tmp.find_first_of('b', 1) == 1);
-  ASSERT_TRUE(Tmp.find_first_of('a', 1) == 3);
-  ASSERT_TRUE(Tmp.find_first_of('a', 42) == string_view::npos);
-  ASSERT_FALSE(Tmp.find_first_of('c') == 1);
-  ASSERT_FALSE(Tmp.find_first_of('c', 0) == 1);
-  ASSERT_FALSE(Tmp.find_first_of('c', 1) == 1);
+TYPED_TEST(LlvmLibcStringViewTest, FindLastOf, TestCharTypes) {
+  using CharT = ParamType;
+  using StringView = LIBC_NAMESPACE::cpp::basic_string_view<CharT>;
+
+  StringView Tmp(ENCODED(CharT, "abada"));
+
+  ASSERT_EQ(Tmp.find_last_of(ENCODED(CharT, 'a')), size_t(4));
+  ASSERT_EQ(Tmp.find_last_of(ENCODED(CharT, 'a'), 123), size_t(4));
+  ASSERT_EQ(Tmp.find_last_of(ENCODED(CharT, 'a'), 5), size_t(4));
+  ASSERT_EQ(Tmp.find_last_of(ENCODED(CharT, 'a'), 4), size_t(4));
+  ASSERT_EQ(Tmp.find_last_of(ENCODED(CharT, 'a'), 3), size_t(2));
+  ASSERT_EQ(Tmp.find_last_of(ENCODED(CharT, 'a'), 2), size_t(2));
+  ASSERT_EQ(Tmp.find_last_of(ENCODED(CharT, 'a'), 1), size_t(0));
+  ASSERT_EQ(Tmp.find_last_of(ENCODED(CharT, 'a'), 0), size_t(0));
+
+  ASSERT_EQ(Tmp.find_last_of(ENCODED(CharT, 'b')), size_t(1));
+  ASSERT_EQ(Tmp.find_last_of(ENCODED(CharT, 'b'), 123), size_t(1));
+  ASSERT_EQ(Tmp.find_last_of(ENCODED(CharT, 'b'), 5), size_t(1));
+  ASSERT_EQ(Tmp.find_last_of(ENCODED(CharT, 'b'), 4), size_t(1));
+  ASSERT_EQ(Tmp.find_last_of(ENCODED(CharT, 'b'), 3), size_t(1));
+  ASSERT_EQ(Tmp.find_last_of(ENCODED(CharT, 'b'), 2), size_t(1));
+  ASSERT_EQ(Tmp.find_last_of(ENCODED(CharT, 'b'), 1), size_t(1));
+  ASSERT_EQ(Tmp.find_last_of(ENCODED(CharT, 'b'), 0), StringView::npos);
+
+  ASSERT_EQ(Tmp.find_last_of(ENCODED(CharT, 'd')), size_t(3));
+  ASSERT_EQ(Tmp.find_last_of(ENCODED(CharT, 'd'), 123), size_t(3));
+  ASSERT_EQ(Tmp.find_last_of(ENCODED(CharT, 'd'), 5), size_t(3));
+  ASSERT_EQ(Tmp.find_last_of(ENCODED(CharT, 'd'), 4), size_t(3));
+  ASSERT_EQ(Tmp.find_last_of(ENCODED(CharT, 'd'), 3), size_t(3));
+  ASSERT_EQ(Tmp.find_last_of(ENCODED(CharT, 'd'), 2), StringView::npos);
+  ASSERT_EQ(Tmp.find_last_of(ENCODED(CharT, 'd'), 1), StringView::npos);
+  ASSERT_EQ(Tmp.find_last_of(ENCODED(CharT, 'd'), 0), StringView::npos);
+
+  ASSERT_EQ(Tmp.find_last_of(ENCODED(CharT, 'e')), StringView::npos);
+  ASSERT_EQ(Tmp.find_last_of(ENCODED(CharT, 'e'), 123), StringView::npos);
+  ASSERT_EQ(Tmp.find_last_of(ENCODED(CharT, 'e'), 5), StringView::npos);
+  ASSERT_EQ(Tmp.find_last_of(ENCODED(CharT, 'e'), 4), StringView::npos);
+  ASSERT_EQ(Tmp.find_last_of(ENCODED(CharT, 'e'), 3), StringView::npos);
+  ASSERT_EQ(Tmp.find_last_of(ENCODED(CharT, 'e'), 2), StringView::npos);
+  ASSERT_EQ(Tmp.find_last_of(ENCODED(CharT, 'e'), 1), StringView::npos);
+  ASSERT_EQ(Tmp.find_last_of(ENCODED(CharT, 'e'), 0), StringView::npos);
+
+  StringView Empty;
+  ASSERT_EQ(Empty.find_last_of(ENCODED(CharT, 'a')), StringView::npos);
+  ASSERT_EQ(Empty.find_last_of(ENCODED(CharT, 'a'), 0), StringView::npos);
+  ASSERT_EQ(Empty.find_last_of(ENCODED(CharT, 'a'), 123), StringView::npos);
+
+  StringView Empty1(ENCODED(CharT, ""));
+  ASSERT_EQ(Empty1.find_last_of(ENCODED(CharT, 'a')), StringView::npos);
+  ASSERT_EQ(Empty1.find_last_of(ENCODED(CharT, 'a'), 0), StringView::npos);
+  ASSERT_EQ(Empty1.find_last_of(ENCODED(CharT, 'a'), 123), StringView::npos);
 }
 
-TEST(LlvmLibcStringViewTest, FindLastOf) {
-  string_view Tmp("abada");
-
-  ASSERT_EQ(Tmp.find_last_of('a'), size_t(4));
-  ASSERT_EQ(Tmp.find_last_of('a', 123), size_t(4));
-  ASSERT_EQ(Tmp.find_last_of('a', 5), size_t(4));
-  ASSERT_EQ(Tmp.find_last_of('a', 4), size_t(4));
-  ASSERT_EQ(Tmp.find_last_of('a', 3), size_t(2));
-  ASSERT_EQ(Tmp.find_last_of('a', 2), size_t(2));
-  ASSERT_EQ(Tmp.find_last_of('a', 1), size_t(0));
-  ASSERT_EQ(Tmp.find_last_of('a', 0), size_t(0));
-
-  ASSERT_EQ(Tmp.find_last_of('b'), size_t(1));
-  ASSERT_EQ(Tmp.find_last_of('b', 123), size_t(1));
-  ASSERT_EQ(Tmp.find_last_of('b', 5), size_t(1));
-  ASSERT_EQ(Tmp.find_last_of('b', 4), size_t(1));
-  ASSERT_EQ(Tmp.find_last_of('b', 3), size_t(1));
-  ASSERT_EQ(Tmp.find_last_of('b', 2), size_t(1));
-  ASSERT_EQ(Tmp.find_last_of('b', 1), size_t(1));
-  ASSERT_EQ(Tmp.find_last_of('b', 0), string_view::npos);
-
-  ASSERT_EQ(Tmp.find_last_of('d'), size_t(3));
-  ASSERT_EQ(Tmp.find_last_of('d', 123), size_t(3));
-  ASSERT_EQ(Tmp.find_last_of('d', 5), size_t(3));
-  ASSERT_EQ(Tmp.find_last_of('d', 4), size_t(3));
-  ASSERT_EQ(Tmp.find_last_of('d', 3), size_t(3));
-  ASSERT_EQ(Tmp.find_last_of('d', 2), string_view::npos);
-  ASSERT_EQ(Tmp.find_last_of('d', 1), string_view::npos);
-  ASSERT_EQ(Tmp.find_last_of('d', 0), string_view::npos);
-
-  ASSERT_EQ(Tmp.find_last_of('e'), string_view::npos);
-  ASSERT_EQ(Tmp.find_last_of('e', 123), string_view::npos);
-  ASSERT_EQ(Tmp.find_last_of('e', 5), string_view::npos);
-  ASSERT_EQ(Tmp.find_last_of('e', 4), string_view::npos);
-  ASSERT_EQ(Tmp.find_last_of('e', 3), string_view::npos);
-  ASSERT_EQ(Tmp.find_last_of('e', 2), string_view::npos);
-  ASSERT_EQ(Tmp.find_last_of('e', 1), string_view::npos);
-  ASSERT_EQ(Tmp.find_last_of('e', 0), string_view::npos);
-
-  string_view Empty;
-  ASSERT_EQ(Empty.find_last_of('a'), string_view::npos);
-  ASSERT_EQ(Empty.find_last_of('a', 0), string_view::npos);
-  ASSERT_EQ(Empty.find_last_of('a', 123), string_view::npos);
-
-  string_view Empty1("");
-  ASSERT_EQ(Empty1.find_last_of('a'), string_view::npos);
-  ASSERT_EQ(Empty1.find_last_of('a', 0), string_view::npos);
-  ASSERT_EQ(Empty1.find_last_of('a', 123), string_view::npos);
+TYPED_TEST(LlvmLibcStringViewTest, FindFirstNotOf, TestCharTypes) {
+  using CharT = ParamType;
+  using StringView = LIBC_NAMESPACE::cpp::basic_string_view<CharT>;
+
+  StringView Tmp(ENCODED(CharT, "abada"));
+
+  EXPECT_EQ(Tmp.find_first_not_of(ENCODED(CharT, 'a')), size_t(1));
+  EXPECT_EQ(Tmp.find_first_not_of(ENCODED(CharT, 'a'), 123), StringView::npos);
+  EXPECT_EQ(Tmp.find_first_not_of(ENCODED(CharT, 'a'), 5), StringView::npos);
+  EXPECT_EQ(Tmp.find_first_not_of(ENCODED(CharT, 'a'), 4), StringView::npos);
+  EXPECT_EQ(Tmp.find_first_not_of(ENCODED(CharT, 'a'), 3), size_t(3));
+  EXPECT_EQ(Tmp.find_first_not_of(ENCODED(CharT, 'a'), 2), size_t(3));
+  EXPECT_EQ(Tmp.find_first_not_of(ENCODED(CharT, 'a'), 1), size_t(1));
+  EXPECT_EQ(Tmp.find_first_not_of(ENCODED(CharT, 'a'), 0), size_t(1));
+
+  EXPECT_EQ(Tmp.find_first_not_of(ENCODED(CharT, 'b')), size_t(0));
+  EXPECT_EQ(Tmp.find_first_not_of(ENCODED(CharT, 'b'), 123), StringView::npos);
+  EXPECT_EQ(Tmp.find_first_not_of(ENCODED(CharT, 'b'), 5), StringView::npos);
+  EXPECT_EQ(Tmp.find_first_not_of(ENCODED(CharT, 'b'), 4), size_t(4));
+  EXPECT_EQ(Tmp.find_first_not_of(ENCODED(CharT, 'b'), 3), size_t(3));
+  EXPECT_EQ(Tmp.find_first_not_of(ENCODED(CharT, 'b'), 2), size_t(2));
+  EXPECT_EQ(Tmp.find_first_not_of(ENCODED(CharT, 'b'), 1), size_t(2));
+  EXPECT_EQ(Tmp.find_first_not_of(ENCODED(CharT, 'b'), 0), size_t(0));
+
+  EXPECT_EQ(Tmp.find_first_not_of(ENCODED(CharT, 'd')), size_t(0));
+  EXPECT_EQ(Tmp.find_first_not_of(ENCODED(CharT, 'd'), 123), StringView::npos);
+  EXPECT_EQ(Tmp.find_first_not_of(ENCODED(CharT, 'd'), 5), StringView::npos);
+  EXPECT_EQ(Tmp.find_first_not_of(ENCODED(CharT, 'd'), 4), size_t(4));
+  EXPECT_EQ(Tmp.find_first_not_of(ENCODED(CharT, 'd'), 3), size_t(4));
+  EXPECT_EQ(Tmp.find_first_not_of(ENCODED(CharT, 'd'), 2), size_t(2));
+  EXPECT_EQ(Tmp.find_first_not_of(ENCODED(CharT, 'd'), 1), size_t(1));
+  EXPECT_EQ(Tmp.find_first_not_of(ENCODED(CharT, 'd'), 0), size_t(0));
+
+  EXPECT_EQ(Tmp.find_first_not_of(ENCODED(CharT, 'e')), size_t(0));
+  EXPECT_EQ(Tmp.find_first_not_of(ENCODED(CharT, 'e'), 123), StringView::npos);
+  EXPECT_EQ(Tmp.find_first_not_of(ENCODED(CharT, 'e'), 5), StringView::npos);
+  EXPECT_EQ(Tmp.find_first_not_of(ENCODED(CharT, 'e'), 4), size_t(4));
+  EXPECT_EQ(Tmp.find_first_not_of(ENCODED(CharT, 'e'), 3), size_t(3));
+  EXPECT_EQ(Tmp.find_first_not_of(ENCODED(CharT, 'e'), 2), size_t(2));
+  EXPECT_EQ(Tmp.find_first_not_of(ENCODED(CharT, 'e'), 1), size_t(1));
+  EXPECT_EQ(Tmp.find_first_not_of(ENCODED(CharT, 'e'), 0), size_t(0));
+
+  StringView Empty;
+  EXPECT_EQ(Empty.find_first_not_of(ENCODED(CharT, 'a')), StringView::npos);
+  EXPECT_EQ(Empty.find_first_not_of(ENCODED(CharT, 'a'), 0), StringView::npos);
+  EXPECT_EQ(Empty.find_first_not_of(ENCODED(CharT, 'a'), 123),
+            StringView::npos);
+
+  StringView Empty1(ENCODED(CharT, ""));
+  EXPECT_EQ(Empty1.find_first_not_of(ENCODED(CharT, 'a')), StringView::npos);
+  EXPECT_EQ(Empty1.find_first_not_of(ENCODED(CharT, 'a'), 0), StringView::npos);
+  EXPECT_EQ(Empty1.find_first_not_of(ENCODED(CharT, 'a'), 123),
+            StringView::npos);
+
+  StringView Full(ENCODED(CharT, "aaaaaaa"));
+  EXPECT_EQ(Full.find_first_not_of(ENCODED(CharT, 'a')), StringView::npos);
+  EXPECT_EQ(Full.find_first_not_of(ENCODED(CharT, 'a'), 0), StringView::npos);
+  EXPECT_EQ(Full.find_first_not_of(ENCODED(CharT, 'a'), 123), StringView::npos);
+
+  EXPECT_EQ(Full.find_first_not_of(ENCODED(CharT, 'b')), size_t(0));
+  EXPECT_EQ(Full.find_first_not_of(ENCODED(CharT, 'b'), 0), size_t(0));
+  EXPECT_EQ(Full.find_first_not_of(ENCODED(CharT, 'b'), 123), StringView::npos);
 }
 
-TEST(LlvmLibcStringViewTest, FindFirstNotOf) {
-  string_view Tmp("abada");
-
-  EXPECT_EQ(Tmp.find_first_not_of('a'), size_t(1));
-  EXPECT_EQ(Tmp.find_first_not_of('a', 123), string_view::npos);
-  EXPECT_EQ(Tmp.find_first_not_of('a', 5), string_view::npos);
-  EXPECT_EQ(Tmp.find_first_not_of('a', 4), string_view::npos);
-  EXPECT_EQ(Tmp.find_first_not_of('a', 3), size_t(3));
-  EXPECT_EQ(Tmp.find_first_not_of('a', 2), size_t(3));
-  EXPECT_EQ(Tmp.find_first_not_of('a', 1), size_t(1));
-  EXPECT_EQ(Tmp.find_first_not_of('a', 0), size_t(1));
-
-  EXPECT_EQ(Tmp.find_first_not_of('b'), size_t(0));
-  EXPECT_EQ(Tmp.find_first_not_of('b', 123), string_view::npos);
-  EXPECT_EQ(Tmp.find_first_not_of('b', 5), string_view::npos);
-  EXPECT_EQ(Tmp.find_first_not_of('b', 4), size_t(4));
-  EXPECT_EQ(Tmp.find_first_not_of('b', 3), size_t(3));
-  EXPECT_EQ(Tmp.find_first_not_of('b', 2), size_t(2));
-  EXPECT_EQ(Tmp.find_first_not_of('b', 1), size_t(2));
-  EXPECT_EQ(Tmp.find_first_not_of('b', 0), size_t(0));
-
-  EXPECT_EQ(Tmp.find_first_not_of('d'), size_t(0));
-  EXPECT_EQ(Tmp.find_first_not_of('d', 123), string_view::npos);
-  EXPECT_EQ(Tmp.find_first_not_of('d', 5), string_view::npos);
-  EXPECT_EQ(Tmp.find_first_not_of('d', 4), size_t(4));
-  EXPECT_EQ(Tmp.find_first_not_of('d', 3), size_t(4));
-  EXPECT_EQ(Tmp.find_first_not_of('d', 2), size_t(2));
-  EXPECT_EQ(Tmp.find_first_not_of('d', 1), size_t(1));
-  EXPECT_EQ(Tmp.find_first_not_of('d', 0), size_t(0));
-
-  EXPECT_EQ(Tmp.find_first_not_of('e'), size_t(0));
-  EXPECT_EQ(Tmp.find_first_not_of('e', 123), string_view::npos);
-  EXPECT_EQ(Tmp.find_first_not_of('e', 5), string_view::npos);
-  EXPECT_EQ(Tmp.find_first_not_of('e', 4), size_t(4));
-  EXPECT_EQ(Tmp.find_first_not_of('e', 3), size_t(3));
-  EXPECT_EQ(Tmp.find_first_not_of('e', 2), size_t(2));
-  EXPECT_EQ(Tmp.find_first_not_of('e', 1), size_t(1));
-  EXPECT_EQ(Tmp.find_first_not_of('e', 0), size_t(0));
-
-  string_view Empty;
-  EXPECT_EQ(Empty.find_first_not_of('a'), string_view::npos);
-  EXPECT_EQ(Empty.find_first_not_of('a', 0), string_view::npos);
-  EXPECT_EQ(Empty.find_first_not_of('a', 123), string_view::npos);
-
-  string_view Empty1("");
-  EXPECT_EQ(Empty1.find_first_not_of('a'), string_view::npos);
-  EXPECT_EQ(Empty1.find_first_not_of('a', 0), string_view::npos);
-  EXPECT_EQ(Empty1.find_first_not_of('a', 123), string_view::npos);
-
-  string_view Full("aaaaaaa");
-  EXPECT_EQ(Full.find_first_not_of('a'), string_view::npos);
-  EXPECT_EQ(Full.find_first_not_of('a', 0), string_view::npos);
-  EXPECT_EQ(Full.find_first_not_of('a', 123), string_view::npos);
-
-  EXPECT_EQ(Full.find_first_not_of('b'), size_t(0));
-  EXPECT_EQ(Full.find_first_not_of('b', 0), size_t(0));
-  EXPECT_EQ(Full.find_first_not_of('b', 123), string_view::npos);
+TYPED_TEST(LlvmLibcStringViewTest, Contains, TestCharTypes) {
+  using CharT = ParamType;
+  using StringView = LIBC_NAMESPACE::cpp::basic_string_view<CharT>;
+
+  StringView Empty;
+  EXPECT_FALSE(Empty.contains(ENCODED(CharT, 'a')));
+  EXPECT_FALSE(Empty.contains(ENCODED(CharT, 'g')));
+  EXPECT_FALSE(Empty.contains(ENCODED(CharT, 'q')));
+
+  StringView S = ENCODED(CharT, "abada");
+  EXPECT_TRUE(S.contains(ENCODED(CharT, 'a')));
+  EXPECT_TRUE(S.contains(ENCODED(CharT, 'b')));
+  EXPECT_FALSE(S.contains(ENCODED(CharT, 'c')));
+  EXPECT_TRUE(S.contains(ENCODED(CharT, 'd')));
+  EXPECT_FALSE(S.contains(ENCODED(CharT, 'e')));
 }
 
-TEST(LlvmLibcStringViewTest, Contains) {
-  string_view Empty;
-  static_assert(
-      'a' < 'z',
-      "This test only supports character encodings where 'a' is below 'z'");
-  for (char c = 'a'; c < 'z'; ++c)
-    EXPECT_FALSE(Empty.contains(c));
-
-  string_view Tmp("abada");
-  EXPECT_TRUE(Tmp.contains('a'));
-  EXPECT_TRUE(Tmp.contains('b'));
-  EXPECT_FALSE(Tmp.contains('c'));
-  EXPECT_TRUE(Tmp.contains('d'));
-  EXPECT_FALSE(Tmp.contains('e'));
-
-  EXPECT_TRUE(Tmp.substr(1).contains('a'));
-  EXPECT_TRUE(Tmp.substr(1).contains('b'));
-  EXPECT_FALSE(Tmp.substr(1).contains('c'));
-  EXPECT_TRUE(Tmp.substr(1).contains('d'));
-  EXPECT_FALSE(Tmp.substr(1).contains('e'));
-
-  EXPECT_TRUE(Tmp.substr(2).contains('a'));
-  EXPECT_FALSE(Tmp.substr(2).contains('b'));
-  EXPECT_FALSE(Tmp.substr(2).contains('c'));
-  EXPECT_TRUE(Tmp.substr(2).contains('d'));
-  EXPECT_FALSE(Tmp.substr(2).contains('e'));
-
-  EXPECT_TRUE(Tmp.substr(3).contains('a'));
-  EXPECT_FALSE(Tmp.substr(3).contains('b'));
-  EXPECT_FALSE(Tmp.substr(3).contains('c'));
-  EXPECT_TRUE(Tmp.substr(3).contains('d'));
-  EXPECT_FALSE(Tmp.substr(3).contains('e'));
-
-  EXPECT_TRUE(Tmp.substr(4).contains('a'));
-  EXPECT_FALSE(Tmp.substr(4).contains('b'));
-  EXPECT_FALSE(Tmp.substr(4).contains('c'));
-  EXPECT_FALSE(Tmp.substr(4).contains('d'));
-  EXPECT_FALSE(Tmp.substr(4).contains('e'));
-
-  EXPECT_FALSE(Tmp.substr(5).contains('a'));
-  EXPECT_FALSE(Tmp.substr(5).contains('b'));
-  EXPECT_FALSE(Tmp.substr(5).contains('c'));
-  EXPECT_FALSE(Tmp.substr(5).contains('d'));
-  EXPECT_FALSE(Tmp.substr(5).contains('e'));
-
-  EXPECT_FALSE(Tmp.substr(6).contains('a'));
-  EXPECT_FALSE(Tmp.substr(6).contains('b'));
-  EXPECT_FALSE(Tmp.substr(6).contains('c'));
-  EXPECT_FALSE(Tmp.substr(6).contains('d'));
-  EXPECT_FALSE(Tmp.substr(6).contains('e'));
+TYPED_TEST(LlvmLibcStringViewTest, Substr, TestCharTypes) {
+  using CharT = ParamType;
+  using StringView = LIBC_NAMESPACE::cpp::basic_string_view<CharT>;
+
+  StringView S = ENCODED(CharT, "abada");
+  EXPECT_EQ(S.substr(0), StringView(ENCODED(CharT, "abada")));
+  EXPECT_EQ(S.substr(1), StringView(ENCODED(CharT, "bada")));
+  EXPECT_EQ(S.substr(3), StringView(ENCODED(CharT, "da")));
+  EXPECT_EQ(S.substr(5), StringView(ENCODED(CharT, "")));
+  EXPECT_EQ(S.substr(1, 3), StringView(ENCODED(CharT, "bad")));
+  EXPECT_EQ(S.substr(3, 1), StringView(ENCODED(CharT, "d")));
+}
+
+TEST(LlvmLibcStringViewTest, WideCharacterComparison) {
+  // Check that wide character comparison is lexicographic by character and not
+  // equivalent to memcmp, which would be incorrect on little endian.
+  char BytesA[] = {1, 2, 3, 4};
+  char BytesB[] = {4, 3, 2, 1};
+  char32_t CharA;
+  char32_t CharB;
+  LIBC_NAMESPACE::inline_memcpy(&CharA, BytesA, sizeof(CharA));
+  LIBC_NAMESPACE::inline_memcpy(&CharB, BytesB, sizeof(CharB));
+
+  LIBC_NAMESPACE::cpp::basic_string_view<char32_t> StringViewA(&CharA, 1);
+  LIBC_NAMESPACE::cpp::basic_string_view<char32_t> StringViewB(&CharB, 1);
+
+  EXPECT_EQ(StringViewA < StringViewB, CharA < CharB);
 }


        


More information about the libc-commits mailing list