Skip to content

Commit f5dcab0

Browse files
committed
[re-reland][libc] Adds string and TestLogger classes, use them in LibcTest
This is an implementation of https://discourse.llvm.org/t/rfc-running-libc-unit-tests-as-integration-tests/69461. Differential Revision: https://reviews.llvm.org/D147231
1 parent fd86789 commit f5dcab0

File tree

11 files changed

+658
-77
lines changed

11 files changed

+658
-77
lines changed

libc/src/__support/CPP/CMakeLists.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,19 @@ add_header_library(
5555
libc.src.__support.common
5656
)
5757

58+
add_header_library(
59+
string
60+
HDRS
61+
string.h
62+
DEPENDS
63+
.string_view
64+
libc.src.__support.common
65+
libc.src.__support.integer_to_string
66+
libc.src.string.memory_utils.memcpy_implementation
67+
libc.src.string.memory_utils.memset_implementation
68+
libc.src.string.string_utils
69+
)
70+
5871
add_header_library(
5972
stringstream
6073
HDRS

libc/src/__support/CPP/string.h

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
//===-- A simple implementation of the string class -------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_LIBC_SRC_SUPPORT_CPP_STRING_H
10+
#define LLVM_LIBC_SRC_SUPPORT_CPP_STRING_H
11+
12+
#include "src/__support/CPP/string_view.h"
13+
#include "src/__support/integer_to_string.h" // IntegerToString
14+
#include "src/string/memory_utils/memcpy_implementations.h"
15+
#include "src/string/memory_utils/memset_implementations.h"
16+
#include "src/string/string_utils.h" // string_length
17+
18+
#include <stddef.h> // size_t
19+
#include <stdlib.h> // malloc, free
20+
21+
namespace __llvm_libc {
22+
namespace cpp {
23+
24+
// This class mimics std::string but does not intend to be a full fledged
25+
// implementation. Most notably it does not provide support for character traits
26+
// nor custom allocator.
27+
class string {
28+
private:
29+
static constexpr char NULL_CHARACTER = '\0';
30+
static constexpr char *get_empty_string() {
31+
return const_cast<char *>(&NULL_CHARACTER);
32+
}
33+
34+
char *buffer_ = get_empty_string();
35+
size_t size_ = 0;
36+
size_t capacity_ = 0;
37+
38+
constexpr void reset_no_deallocate() {
39+
buffer_ = get_empty_string();
40+
size_ = 0;
41+
capacity_ = 0;
42+
}
43+
44+
void set_size_and_add_null_character(size_t size) {
45+
size_ = size;
46+
if (buffer_ != get_empty_string())
47+
buffer_[size_] = NULL_CHARACTER;
48+
}
49+
50+
public:
51+
LIBC_INLINE constexpr string() {}
52+
LIBC_INLINE string(const string &other) { this->operator+=(other); }
53+
LIBC_INLINE constexpr string(string &&other)
54+
: buffer_(other.buffer_), size_(other.size_), capacity_(other.capacity_) {
55+
other.reset_no_deallocate();
56+
}
57+
LIBC_INLINE string(const char *cstr, size_t count) {
58+
resize(count);
59+
inline_memcpy((void *)buffer_, (const void *)cstr, count);
60+
}
61+
LIBC_INLINE string(const char *cstr)
62+
: string(cstr, ::__llvm_libc::internal::string_length(cstr)) {}
63+
LIBC_INLINE string(size_t size_, char value) {
64+
resize(size_);
65+
inline_memset((void *)buffer_, value, size_);
66+
}
67+
68+
LIBC_INLINE string &operator=(const string &other) {
69+
resize(0);
70+
return (*this) += other;
71+
}
72+
73+
LIBC_INLINE string &operator=(string &&other) {
74+
buffer_ = other.buffer_;
75+
size_ = other.size_;
76+
capacity_ = other.capacity_;
77+
other.reset_no_deallocate();
78+
return *this;
79+
}
80+
81+
LIBC_INLINE ~string() {
82+
if (buffer_ != get_empty_string())
83+
::free(buffer_);
84+
}
85+
86+
LIBC_INLINE constexpr size_t capacity() const { return capacity_; }
87+
LIBC_INLINE constexpr size_t size() const { return size_; }
88+
LIBC_INLINE constexpr bool empty() const { return size_ == 0; }
89+
90+
LIBC_INLINE constexpr const char *data() const { return buffer_; }
91+
LIBC_INLINE char *data() { return buffer_; }
92+
93+
LIBC_INLINE constexpr const char *begin() const { return data(); }
94+
LIBC_INLINE char *begin() { return data(); }
95+
96+
LIBC_INLINE constexpr const char *end() const { return data() + size_; }
97+
LIBC_INLINE char *end() { return data() + size_; }
98+
99+
LIBC_INLINE constexpr const char &front() const { return data()[0]; }
100+
LIBC_INLINE char &front() { return data()[0]; }
101+
102+
LIBC_INLINE constexpr const char &back() const { return data()[size_ - 1]; }
103+
LIBC_INLINE char &back() { return data()[size_ - 1]; }
104+
105+
LIBC_INLINE constexpr const char &operator[](size_t index) const {
106+
return data()[index];
107+
}
108+
LIBC_INLINE char &operator[](size_t index) { return data()[index]; }
109+
110+
LIBC_INLINE const char *c_str() const { return data(); }
111+
112+
LIBC_INLINE operator string_view() const {
113+
return string_view(buffer_, size_);
114+
}
115+
116+
LIBC_INLINE void reserve(size_t new_capacity) {
117+
++new_capacity; // Accounting for the terminating '\0'
118+
if (new_capacity <= capacity_)
119+
return;
120+
// We extend the capacity to amortize buffer_ reallocations.
121+
// We choose to augment the value by 11 / 8, this is about +40% and division
122+
// by 8 is cheap. We guard the extension so the operation doesn't overflow.
123+
if (new_capacity < SIZE_MAX / 11)
124+
new_capacity = new_capacity * 11 / 8;
125+
if (void *Ptr = ::realloc(buffer_ == get_empty_string() ? nullptr : buffer_,
126+
new_capacity)) {
127+
buffer_ = static_cast<char *>(Ptr);
128+
capacity_ = new_capacity;
129+
} else {
130+
__builtin_unreachable(); // out of memory
131+
}
132+
}
133+
134+
LIBC_INLINE void resize(size_t size) {
135+
if (size > capacity_) {
136+
reserve(size);
137+
const size_t size_extension = size - size_;
138+
inline_memset(data() + size_, '\0', size_extension);
139+
}
140+
set_size_and_add_null_character(size);
141+
}
142+
143+
LIBC_INLINE string &operator+=(const string &rhs) {
144+
const size_t new_size = size_ + rhs.size();
145+
reserve(new_size);
146+
inline_memcpy(buffer_ + size_, rhs.data(), rhs.size());
147+
set_size_and_add_null_character(new_size);
148+
return *this;
149+
}
150+
151+
LIBC_INLINE string &operator+=(const char c) {
152+
const size_t new_size = size_ + 1;
153+
reserve(new_size);
154+
buffer_[size_] = c;
155+
set_size_and_add_null_character(new_size);
156+
return *this;
157+
}
158+
};
159+
160+
LIBC_INLINE bool operator==(const string &lhs, const string &rhs) {
161+
return string_view(lhs) == string_view(rhs);
162+
}
163+
LIBC_INLINE bool operator!=(const string &lhs, const string &rhs) {
164+
return string_view(lhs) != string_view(rhs);
165+
}
166+
LIBC_INLINE bool operator<(const string &lhs, const string &rhs) {
167+
return string_view(lhs) < string_view(rhs);
168+
}
169+
LIBC_INLINE bool operator<=(const string &lhs, const string &rhs) {
170+
return string_view(lhs) <= string_view(rhs);
171+
}
172+
LIBC_INLINE bool operator>(const string &lhs, const string &rhs) {
173+
return string_view(lhs) > string_view(rhs);
174+
}
175+
LIBC_INLINE bool operator>=(const string &lhs, const string &rhs) {
176+
return string_view(lhs) >= string_view(rhs);
177+
}
178+
179+
LIBC_INLINE string operator+(const string &lhs, const string &rhs) {
180+
string Tmp(lhs);
181+
return Tmp += rhs;
182+
}
183+
LIBC_INLINE string operator+(const string &lhs, const char *rhs) {
184+
return lhs + string(rhs);
185+
}
186+
LIBC_INLINE string operator+(const char *lhs, const string &rhs) {
187+
return string(lhs) + rhs;
188+
}
189+
190+
namespace internal {
191+
template <typename T> string to_dec_string(T value) {
192+
char dec_buf[IntegerToString::dec_bufsize<T>()];
193+
auto maybe_string_view = IntegerToString::dec(value, dec_buf);
194+
const auto &string_view = *maybe_string_view;
195+
return string(string_view.data(), string_view.size());
196+
}
197+
} // namespace internal
198+
199+
LIBC_INLINE string to_string(int value) {
200+
return internal::to_dec_string<int>(value);
201+
}
202+
LIBC_INLINE string to_string(long value) {
203+
return internal::to_dec_string<long>(value);
204+
}
205+
LIBC_INLINE string to_string(long long value) {
206+
return internal::to_dec_string<long long>(value);
207+
}
208+
LIBC_INLINE string to_string(unsigned value) {
209+
return internal::to_dec_string<unsigned>(value);
210+
}
211+
LIBC_INLINE string to_string(unsigned long value) {
212+
return internal::to_dec_string<unsigned long>(value);
213+
}
214+
LIBC_INLINE string to_string(unsigned long long value) {
215+
return internal::to_dec_string<unsigned long long>(value);
216+
}
217+
218+
// TODO: Support floating point
219+
// LIBC_INLINE string to_string(float value);
220+
// LIBC_INLINE string to_string(double value);
221+
// LIBC_INLINE string to_string(long double value);
222+
223+
} // namespace cpp
224+
} // namespace __llvm_libc
225+
226+
#endif // LLVM_LIBC_SRC_SUPPORT_CPP_STRING_H

libc/test/UnitTest/CMakeLists.txt

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,29 @@
1+
add_library(
2+
TestLogger
3+
TestLogger.cpp
4+
TestLogger.h
5+
)
6+
target_include_directories(TestLogger PUBLIC ${LIBC_SOURCE_DIR})
7+
add_dependencies(TestLogger
8+
libc.src.__support.CPP.string
9+
libc.src.__support.CPP.string_view
10+
libc.src.__support.OSUtil.osutil
11+
)
12+
113
add_library(
214
LibcUnitTest
315
Test.h
416
LibcTest.cpp
517
LibcTest.h
618
)
719
target_include_directories(LibcUnitTest PUBLIC ${LIBC_SOURCE_DIR})
8-
add_dependencies(LibcUnitTest libc.src.__support.CPP.type_traits libc.src.__support.uint128)
9-
target_link_libraries(LibcUnitTest PUBLIC libc_test_utils)
20+
add_dependencies(
21+
LibcUnitTest
22+
libc.src.__support.CPP.string
23+
libc.src.__support.CPP.string_view
24+
libc.src.__support.CPP.type_traits
25+
libc.src.__support.uint128 TestLogger)
26+
target_link_libraries(LibcUnitTest PUBLIC libc_test_utils TestLogger)
1027

1128
add_library(
1229
LibcUnitTestMain
@@ -20,17 +37,17 @@ target_link_libraries(LibcUnitTestMain PUBLIC LibcUnitTest libc_test_utils)
2037
add_header_library(
2138
string_utils
2239
HDRS
23-
StringUtils.h
40+
StringUtils.h
2441
DEPENDS
2542
libc.src.__support.CPP.type_traits
2643
)
2744

2845
add_library(
2946
LibcFPTestHelpers
30-
FPExceptMatcher.cpp
31-
FPExceptMatcher.h
32-
FPMatcher.cpp
33-
FPMatcher.h
47+
FPExceptMatcher.cpp
48+
FPExceptMatcher.h
49+
FPMatcher.cpp
50+
FPMatcher.h
3451
)
3552
target_include_directories(LibcFPTestHelpers PUBLIC ${LIBC_SOURCE_DIR})
3653
target_link_libraries(LibcFPTestHelpers LibcUnitTest libc_test_utils)
@@ -44,8 +61,8 @@ add_dependencies(
4461

4562
add_library(
4663
LibcMemoryHelpers
47-
MemoryMatcher.h
48-
MemoryMatcher.cpp
64+
MemoryMatcher.h
65+
MemoryMatcher.cpp
4966
)
5067
target_include_directories(LibcMemoryHelpers PUBLIC ${LIBC_SOURCE_DIR})
5168
target_link_libraries(LibcMemoryHelpers LibcUnitTest)
@@ -57,8 +74,8 @@ add_dependencies(
5774

5875
add_library(
5976
LibcPrintfHelpers
60-
PrintfMatcher.h
61-
PrintfMatcher.cpp
77+
PrintfMatcher.h
78+
PrintfMatcher.cpp
6279
)
6380
target_include_directories(LibcPrintfHelpers PUBLIC ${LIBC_SOURCE_DIR})
6481
target_link_libraries(LibcPrintfHelpers LibcUnitTest)
@@ -72,8 +89,8 @@ add_dependencies(
7289

7390
add_library(
7491
LibcScanfHelpers
75-
ScanfMatcher.h
76-
ScanfMatcher.cpp
92+
ScanfMatcher.h
93+
ScanfMatcher.cpp
7794
)
7895
target_include_directories(LibcScanfHelpers PUBLIC ${LIBC_SOURCE_DIR})
7996
target_link_libraries(LibcScanfHelpers LibcUnitTest)

0 commit comments

Comments
 (0)