122 changes: 60 additions & 62 deletions libc/test/UnitTest/LibcTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@

#include "LibcTest.h"

#include "src/__support/CPP/string.h"
#include "src/__support/CPP/string_view.h"
#include "src/__support/UInt128.h"
#include "test/UnitTest/TestLogger.h"
#include "utils/testutils/ExecuteFunction.h"
#include <cassert>
#include <iostream>
#include <string>

namespace __llvm_libc {
namespace testing {
Expand Down Expand Up @@ -41,58 +41,56 @@ namespace internal {
// be able to unittest UInt<128> on platforms where UInt128 resolves to
// UInt128.
template <typename T>
cpp::enable_if_t<cpp::is_integral_v<T> && cpp::is_unsigned_v<T>, std::string>
cpp::enable_if_t<cpp::is_integral_v<T> && cpp::is_unsigned_v<T>, cpp::string>
describeValueUInt(T Value) {
static_assert(sizeof(T) % 8 == 0, "Unsupported size of UInt");
std::string S(sizeof(T) * 2, '0');
cpp::string S(sizeof(T) * 2, '0');

constexpr char HEXADECIMALS[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

for (auto I = S.rbegin(), End = S.rend(); I != End; ++I, Value >>= 8) {
const size_t Size = S.size();
for (size_t I = 0; I < Size; I += 2, Value >>= 8) {
unsigned char Mod = static_cast<unsigned char>(Value) & 0xFF;
*(I++) = HEXADECIMALS[Mod & 0x0F];
*I = HEXADECIMALS[Mod >> 4];
S[Size - I] = HEXADECIMALS[Mod & 0x0F];
S[Size - (I + 1)] = HEXADECIMALS[Mod & 0x0F];
}

return "0x" + S;
}

// When the value is of integral type, just display it as normal.
template <typename ValType>
cpp::enable_if_t<cpp::is_integral_v<ValType>, std::string>
cpp::enable_if_t<cpp::is_integral_v<ValType>, cpp::string>
describeValue(ValType Value) {
if constexpr (sizeof(ValType) <= sizeof(uint64_t)) {
return std::to_string(Value);
return cpp::to_string(Value);
} else {
return describeValueUInt(Value);
}
}

std::string describeValue(std::string Value) { return std::string(Value); }
std::string describeValue(cpp::string_view Value) {
return std::string(Value.data(), Value.size());
}
cpp::string describeValue(cpp::string Value) { return Value; }
cpp::string_view describeValue(cpp::string_view Value) { return Value; }

template <typename ValType>
void explainDifference(ValType LHS, ValType RHS, const char *LHSStr,
const char *RHSStr, const char *File, unsigned long Line,
std::string OpString) {
cpp::string OpString) {
size_t OffsetLength = OpString.size() > 2 ? OpString.size() - 2 : 0;
std::string Offset(OffsetLength, ' ');
cpp::string Offset(OffsetLength, ' ');

std::cout << File << ":" << Line << ": FAILURE\n"
<< Offset << "Expected: " << LHSStr << '\n'
<< Offset << "Which is: " << describeValue(LHS) << '\n'
<< "To be " << OpString << ": " << RHSStr << '\n'
<< Offset << "Which is: " << describeValue(RHS) << '\n';
tlog << File << ":" << Line << ": FAILURE\n"
<< Offset << "Expected: " << LHSStr << '\n'
<< Offset << "Which is: " << describeValue(LHS) << '\n'
<< "To be " << OpString << ": " << RHSStr << '\n'
<< Offset << "Which is: " << describeValue(RHS) << '\n';
}

template <typename ValType>
bool test(RunContext *Ctx, TestCondition Cond, ValType LHS, ValType RHS,
const char *LHSStr, const char *RHSStr, const char *File,
unsigned long Line) {
auto ExplainDifference = [=](std::string OpString) {
auto ExplainDifference = [=](cpp::string OpString) {
explainDifference(LHS, RHS, LHSStr, RHSStr, File, Line, OpString);
};

Expand Down Expand Up @@ -141,7 +139,7 @@ bool test(RunContext *Ctx, TestCondition Cond, ValType LHS, ValType RHS,
return false;
default:
Ctx->markFail();
std::cout << "Unexpected test condition.\n";
tlog << "Unexpected test condition.\n";
return false;
}
}
Expand All @@ -167,14 +165,14 @@ int Test::runTests(const char *TestFilter) {
int FailCount = 0;
for (Test *T = Start; T != nullptr; T = T->Next) {
const char *TestName = T->getName();
std::string StrTestName(TestName);
cpp::string StrTestName(TestName);
constexpr auto GREEN = "\033[32m";
constexpr auto RED = "\033[31m";
constexpr auto RESET = "\033[0m";
if ((TestFilter != nullptr) && (StrTestName != TestFilter)) {
continue;
}
std::cout << GREEN << "[ RUN ] " << RESET << TestName << '\n';
tlog << GREEN << "[ RUN ] " << RESET << TestName << '\n';
RunContext Ctx;
T->SetUp();
T->setContext(&Ctx);
Expand All @@ -183,24 +181,24 @@ int Test::runTests(const char *TestFilter) {
auto Result = Ctx.status();
switch (Result) {
case RunContext::Result_Fail:
std::cout << RED << "[ FAILED ] " << RESET << TestName << '\n';
tlog << RED << "[ FAILED ] " << RESET << TestName << '\n';
++FailCount;
break;
case RunContext::Result_Pass:
std::cout << GREEN << "[ OK ] " << RESET << TestName << '\n';
tlog << GREEN << "[ OK ] " << RESET << TestName << '\n';
break;
}
++TestCount;
}

if (TestCount > 0) {
std::cout << "Ran " << TestCount << " tests. "
<< " PASS: " << TestCount - FailCount << ' '
<< " FAIL: " << FailCount << '\n';
tlog << "Ran " << TestCount << " tests. "
<< " PASS: " << TestCount - FailCount << ' ' << " FAIL: " << FailCount
<< '\n';
} else {
std::cout << "No tests run.\n";
tlog << "No tests run.\n";
if (TestFilter) {
std::cout << "No matching test for " << TestFilter << '\n';
tlog << "No matching test for " << TestFilter << '\n';
}
}

Expand Down Expand Up @@ -302,15 +300,15 @@ template bool test<__llvm_libc::cpp::string_view>(

bool Test::testStrEq(const char *LHS, const char *RHS, const char *LHSStr,
const char *RHSStr, const char *File, unsigned long Line) {
return internal::test(Ctx, Cond_EQ, LHS ? std::string(LHS) : std::string(),
RHS ? std::string(RHS) : std::string(), LHSStr, RHSStr,
return internal::test(Ctx, Cond_EQ, LHS ? cpp::string(LHS) : cpp::string(),
RHS ? cpp::string(RHS) : cpp::string(), LHSStr, RHSStr,
File, Line);
}

bool Test::testStrNe(const char *LHS, const char *RHS, const char *LHSStr,
const char *RHSStr, const char *File, unsigned long Line) {
return internal::test(Ctx, Cond_NE, LHS ? std::string(LHS) : std::string(),
RHS ? std::string(RHS) : std::string(), LHSStr, RHSStr,
return internal::test(Ctx, Cond_NE, LHS ? cpp::string(LHS) : cpp::string(),
RHS ? cpp::string(RHS) : cpp::string(), LHSStr, RHSStr,
File, Line);
}

Expand All @@ -321,8 +319,8 @@ bool Test::testMatch(bool MatchResult, MatcherBase &Matcher, const char *LHSStr,

Ctx->markFail();
if (!Matcher.is_silent()) {
std::cout << File << ":" << Line << ": FAILURE\n"
<< "Failed to match " << LHSStr << " against " << RHSStr << ".\n";
tlog << File << ":" << Line << ": FAILURE\n"
<< "Failed to match " << LHSStr << " against " << RHSStr << ".\n";
testutils::StreamWrapper OutsWrapper = testutils::outs();
Matcher.explainError(OutsWrapper);
}
Expand All @@ -338,22 +336,22 @@ bool Test::testProcessKilled(testutils::FunctionCaller *Func, int Signal,

if (const char *error = Result.get_error()) {
Ctx->markFail();
std::cout << File << ":" << Line << ": FAILURE\n" << error << '\n';
tlog << File << ":" << Line << ": FAILURE\n" << error << '\n';
return false;
}

if (Result.timed_out()) {
Ctx->markFail();
std::cout << File << ":" << Line << ": FAILURE\n"
<< "Process timed out after " << 500 << " milliseconds.\n";
tlog << File << ":" << Line << ": FAILURE\n"
<< "Process timed out after " << 500 << " milliseconds.\n";
return false;
}

if (Result.exited_normally()) {
Ctx->markFail();
std::cout << File << ":" << Line << ": FAILURE\n"
<< "Expected " << LHSStr
<< " to be killed by a signal\nBut it exited normally!\n";
tlog << File << ":" << Line << ": FAILURE\n"
<< "Expected " << LHSStr
<< " to be killed by a signal\nBut it exited normally!\n";
return false;
}

Expand All @@ -364,12 +362,12 @@ bool Test::testProcessKilled(testutils::FunctionCaller *Func, int Signal,

using testutils::signal_as_string;
Ctx->markFail();
std::cout << File << ":" << Line << ": FAILURE\n"
<< " Expected: " << LHSStr << '\n'
<< "To be killed by signal: " << Signal << '\n'
<< " Which is: " << signal_as_string(Signal) << '\n'
<< " But it was killed by: " << KilledBy << '\n'
<< " Which is: " << signal_as_string(KilledBy) << '\n';
tlog << File << ":" << Line << ": FAILURE\n"
<< " Expected: " << LHSStr << '\n'
<< "To be killed by signal: " << Signal << '\n'
<< " Which is: " << signal_as_string(Signal) << '\n'
<< " But it was killed by: " << KilledBy << '\n'
<< " Which is: " << signal_as_string(KilledBy) << '\n';
return false;
}

Expand All @@ -380,23 +378,23 @@ bool Test::testProcessExits(testutils::FunctionCaller *Func, int ExitCode,

if (const char *error = Result.get_error()) {
Ctx->markFail();
std::cout << File << ":" << Line << ": FAILURE\n" << error << '\n';
tlog << File << ":" << Line << ": FAILURE\n" << error << '\n';
return false;
}

if (Result.timed_out()) {
Ctx->markFail();
std::cout << File << ":" << Line << ": FAILURE\n"
<< "Process timed out after " << 500 << " milliseconds.\n";
tlog << File << ":" << Line << ": FAILURE\n"
<< "Process timed out after " << 500 << " milliseconds.\n";
return false;
}

if (!Result.exited_normally()) {
Ctx->markFail();
std::cout << File << ":" << Line << ": FAILURE\n"
<< "Expected " << LHSStr << '\n'
<< "to exit with exit code " << ExitCode << '\n'
<< "But it exited abnormally!\n";
tlog << File << ":" << Line << ": FAILURE\n"
<< "Expected " << LHSStr << '\n'
<< "to exit with exit code " << ExitCode << '\n'
<< "But it exited abnormally!\n";
return false;
}

Expand All @@ -405,11 +403,11 @@ bool Test::testProcessExits(testutils::FunctionCaller *Func, int ExitCode,
return true;

Ctx->markFail();
std::cout << File << ":" << Line << ": FAILURE\n"
<< "Expected exit code of: " << LHSStr << '\n'
<< " Which is: " << ActualExit << '\n'
<< " To be equal to: " << RHSStr << '\n'
<< " Which is: " << ExitCode << '\n';
tlog << File << ":" << Line << ": FAILURE\n"
<< "Expected exit code of: " << LHSStr << '\n'
<< " Which is: " << ActualExit << '\n'
<< " To be equal to: " << RHSStr << '\n'
<< " Which is: " << ExitCode << '\n';
return false;
}

Expand Down
9 changes: 9 additions & 0 deletions libc/test/UnitTest/LibcTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include "PlatformDefs.h"

#include "src/__support/CPP/string.h"
#include "src/__support/CPP/string_view.h"
#include "src/__support/CPP/type_traits.h"
#include "utils/testutils/ExecuteFunction.h"
Expand Down Expand Up @@ -119,6 +120,14 @@ class Test {
return internal::test(Ctx, Cond, LHS, RHS, LHSStr, RHSStr, File, Line);
}

template <typename ValType,
cpp::enable_if_t<cpp::is_same_v<ValType, __llvm_libc::cpp::string>,
int> = 0>
bool test(TestCondition Cond, ValType LHS, ValType RHS, const char *LHSStr,
const char *RHSStr, const char *File, unsigned long Line) {
return internal::test(Ctx, Cond, LHS, RHS, LHSStr, RHSStr, File, Line);
}

bool testStrEq(const char *LHS, const char *RHS, const char *LHSStr,
const char *RHSStr, const char *File, unsigned long Line);

Expand Down
49 changes: 49 additions & 0 deletions libc/test/UnitTest/TestLogger.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#include "test/UnitTest/TestLogger.h"
#include "src/__support/CPP/string.h"
#include "src/__support/CPP/string_view.h"
#include "src/__support/OSUtil/io.h" //write_to_stderr

namespace __llvm_libc {
namespace testing {

// cpp::string_view specialization
template <>
TestLogger &TestLogger::operator<< <cpp::string_view>(cpp::string_view str) {
__llvm_libc::write_to_stderr(str);
return *this;
}

// cpp::string specialization
template <> TestLogger &TestLogger::operator<< <cpp::string>(cpp::string str) {
return *this << static_cast<cpp::string_view>(str);
}

// const char* specialization
template <> TestLogger &TestLogger::operator<< <const char *>(const char *str) {
return *this << cpp::string_view(str);
}

// char specialization
template <> TestLogger &TestLogger::operator<<(char ch) {
return *this << cpp::string_view(&ch, 1);
}

template <typename T> TestLogger &TestLogger::operator<<(T t) {
return *this << cpp::to_string(t);
}

// is_integral specializations
template TestLogger &TestLogger::operator<< <int>(int);
template TestLogger &TestLogger::operator<< <unsigned int>(unsigned int);
template TestLogger &TestLogger::operator<< <long>(long);
template TestLogger &TestLogger::operator<< <unsigned long>(unsigned long);
template TestLogger &TestLogger::operator<< <long long>(long long);
template TestLogger &
TestLogger::operator<< <unsigned long long>(unsigned long long);

// TODO: Add floating point formatting once it's supported by StringStream.

TestLogger tlog;

} // namespace testing
} // namespace __llvm_libc
27 changes: 27 additions & 0 deletions libc/test/UnitTest/TestLogger.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//===-- Utilities to log to standard output during tests --------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_TEST_UNITTEST_TESTLOGGER_H
#define LLVM_LIBC_TEST_UNITTEST_TESTLOGGER_H

namespace __llvm_libc {
namespace testing {

// A class to log to standard output in the context of hermetic tests.
struct TestLogger {
constexpr TestLogger() = default;
template <typename T> TestLogger &operator<<(T);
};

// A global TestLogger instance to be used in tests.
extern TestLogger tlog;

} // namespace testing
} // namespace __llvm_libc

#endif /* LLVM_LIBC_TEST_UNITTEST_TESTLOGGER_H */
15 changes: 13 additions & 2 deletions libc/test/src/__support/CPP/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ add_libc_unittest(
SRCS
optional_test.cpp
DEPENDS
libc.src.__support.CPP.optional
libc.src.__support.CPP.optional
)

add_libc_unittest(
Expand All @@ -89,5 +89,16 @@ add_libc_unittest(
SRCS
span_test.cpp
DEPENDS
libc.src.__support.CPP.span
libc.src.__support.CPP.span
)

add_libc_unittest(
string_test
SUITE
libc_cpp_utils_unittests
SRCS
string_test.cpp
DEPENDS
libc.src.__support.CPP.string
libc.src.__support.CPP.string_view
)
198 changes: 198 additions & 0 deletions libc/test/src/__support/CPP/string_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
//===-- Unittests for string ----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/__support/CPP/string.h"
#include "test/UnitTest/Test.h"

using __llvm_libc::cpp::string;
using __llvm_libc::cpp::string_view;
using __llvm_libc::cpp::to_string;

TEST(LlvmLibcStringTest, InitializeEmpty) {
const string s;
ASSERT_EQ(s.size(), size_t(0));
ASSERT_TRUE(s.empty());
ASSERT_STREQ(s.data(), "");
ASSERT_STREQ(s.c_str(), "");
ASSERT_EQ(s.data(), s.c_str());
ASSERT_EQ(s.capacity(), size_t(0));
}

TEST(LlvmLibcStringTest, InitializeCString) {
const char *const str = "abc";
const string s(str);
ASSERT_EQ(s.size(), size_t(3));
ASSERT_FALSE(s.empty());
ASSERT_NE(s.data(), &str[0]);
ASSERT_EQ(s[0], 'a');
ASSERT_EQ(s[1], 'b');
ASSERT_EQ(s[2], 'c');
ASSERT_EQ(s.front(), 'a');
ASSERT_EQ(s.back(), 'c');
ASSERT_EQ(s.data(), s.c_str());
}

TEST(LlvmLibcStringTest, ToCString) {
const char *const str = "abc";
string s(str);
const char *cstr = s.c_str();
ASSERT_EQ(s.size(), size_t(3));
ASSERT_STREQ(str, cstr);
}

TEST(LlvmLibcStringTest, ToStringView) {
const char *const str = "abc";
string s(str);
string_view view = s;
ASSERT_EQ(view, string_view(str));
}

TEST(LlvmLibcStringTest, InitializeCStringWithSize) {
const char *const str = "abc";
const string s(str, 2);
ASSERT_EQ(s.size(), size_t(2));
ASSERT_EQ(s[0], 'a');
ASSERT_EQ(s[1], 'b');
ASSERT_EQ(s.front(), 'a');
ASSERT_EQ(s.back(), 'b');
}

TEST(LlvmLibcStringTest, InitializeRepeatedChar) {
const string s(4, '1');
ASSERT_EQ(string_view(s), string_view("1111"));
}

TEST(LlvmLibcStringTest, InitializeZeorChar) {
const string s(0, '1');
ASSERT_TRUE(s.empty());
}

TEST(LlvmLibcStringTest, CopyConstruct) {
const char *const str = "abc";
string a(str);
string b(a);
// Same content
ASSERT_STREQ(a.c_str(), str);
ASSERT_STREQ(b.c_str(), str);
// Different pointers
ASSERT_NE(a.data(), b.data());
}

string &&move(string &value) { return static_cast<string &&>(value); }

TEST(LlvmLibcStringTest, CopyAssign) {
const char *const str = "abc";
string a(str);
string b;
b = a;
// Same content
ASSERT_STREQ(a.c_str(), str);
ASSERT_STREQ(b.c_str(), str);
// Different pointers
ASSERT_NE(a.data(), b.data());
}

TEST(LlvmLibcStringTest, MoveConstruct) {
const char *const str = "abc";
string a(str);
string b(move(a));
ASSERT_STREQ(b.c_str(), str);
ASSERT_STREQ(a.c_str(), "");
}

TEST(LlvmLibcStringTest, MoveAssign) {
const char *const str = "abc";
string a(str);
string b;
b = move(a);
ASSERT_STREQ(b.c_str(), str);
ASSERT_STREQ(a.c_str(), "");
}

TEST(LlvmLibcStringTest, Concat) {
const char *const str = "abc";
string a(str);
string b;
b += a;
ASSERT_STREQ(b.c_str(), "abc");
b += a;
ASSERT_STREQ(b.c_str(), "abcabc");
}

TEST(LlvmLibcStringTest, AddChar) {
string a;
a += 'a';
ASSERT_STREQ(a.c_str(), "a");
a += 'b';
ASSERT_STREQ(a.c_str(), "ab");
}

TEST(LlvmLibcStringTest, ResizeCapacityAndNullTermination) {
string a;
// Empty
ASSERT_EQ(a.capacity(), size_t(0));
ASSERT_EQ(a.data()[0], '\0');
// Still empty
a.resize(0);
ASSERT_EQ(a.capacity(), size_t(0));
ASSERT_EQ(a.data()[0], '\0');
// One char
a.resize(1);
ASSERT_EQ(a.size(), size_t(1));
ASSERT_GE(a.capacity(), size_t(2));
ASSERT_EQ(a.data()[1], '\0');
// Clear
a.resize(0);
ASSERT_EQ(a.size(), size_t(0));
ASSERT_GE(a.capacity(), size_t(2));
ASSERT_EQ(a.data()[0], '\0');
}

TEST(LlvmLibcStringTest, ConcatWithCString) {
ASSERT_STREQ((string("a") + string("b")).c_str(), "ab");
ASSERT_STREQ((string("a") + "b").c_str(), "ab");
ASSERT_STREQ(("a" + string("b")).c_str(), "ab");
}

TEST(LlvmLibcStringTest, Comparison) {
// Here we simply check that comparison of string and string_view have the
// same semantic.
struct CStringPair {
const char *const a;
const char *const b;
} kTestPairs[] = {{"a", "b"}, {"", "xyz"}};
for (const auto [pa, pb] : kTestPairs) {
const string sa(pa);
const string sb(pb);
const string_view sva(pa);
const string_view svb(pb);
ASSERT_EQ(sa == sb, sva == svb);
ASSERT_EQ(sa != sb, sva != svb);
ASSERT_EQ(sa >= sb, sva >= svb);
ASSERT_EQ(sa <= sb, sva <= svb);
ASSERT_EQ(sa < sb, sva < svb);
ASSERT_EQ(sa > sb, sva > svb);
}
}

TEST(LlvmLibcStringTest, ToString) {
struct CStringPair {
const int value;
const string str;
} kTestPairs[] = {{123, "123"}, {0, "0"}, {-321, "-321"}};
for (const auto &[value, str] : kTestPairs) {
ASSERT_EQ(to_string((int)(value)), str);
ASSERT_EQ(to_string((long)(value)), str);
ASSERT_EQ(to_string((long long)(value)), str);
if (value >= 0) {
ASSERT_EQ(to_string((unsigned int)(value)), str);
ASSERT_EQ(to_string((unsigned long)(value)), str);
ASSERT_EQ(to_string((unsigned long long)(value)), str);
}
}
}
13 changes: 13 additions & 0 deletions utils/bazel/llvm-project-overlay/libc/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,19 @@ libc_support_library(
],
)

libc_support_library(
name = "__support_cpp_string",
hdrs = ["src/__support/CPP/string.h"],
deps = [
":__support_common",
":__support_cpp_string_view",
":__support_integer_to_string",
":libc_root",
":string_memory_utils",
":string_utils",
],
)

libc_support_library(
name = "__support_cpp_type_traits",
hdrs = ["src/__support/CPP/type_traits.h"],
Expand Down
14 changes: 14 additions & 0 deletions utils/bazel/llvm-project-overlay/libc/test/UnitTest/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,18 @@ package(default_visibility = ["//visibility:public"])

licenses(["notice"])

cc_library(
name = "test_logger",
srcs = ["TestLogger.cpp"],
hdrs = ["TestLogger.h"],
deps = [
"//libc:__support_cpp_string",
"//libc:__support_cpp_string_view",
"//libc:__support_osutil_io",
"//libc:libc_root",
],
)

cc_library(
name = "LibcUnitTest",
srcs = [
Expand All @@ -20,9 +32,11 @@ cc_library(
"Test.h",
],
deps = [
":test_logger",
"//libc:__support_cpp_bit",
"//libc:__support_cpp_bitset",
"//libc:__support_cpp_span",
"//libc:__support_cpp_string",
"//libc:__support_cpp_string_view",
"//libc:__support_cpp_type_traits",
"//libc:__support_uint128",
Expand Down