1 //===-- A simple implementation of the string class -------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_LIBC_SRC_SUPPORT_CPP_STRING_H
10 #define LLVM_LIBC_SRC_SUPPORT_CPP_STRING_H
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
18 #include <stddef.h> // size_t
19 #include <stdlib.h> // malloc, free
21 namespace __llvm_libc
{
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.
29 static constexpr char NULL_CHARACTER
= '\0';
30 static constexpr char *get_empty_string() {
31 return const_cast<char *>(&NULL_CHARACTER
);
34 char *buffer_
= get_empty_string();
38 constexpr void reset_no_deallocate() {
39 buffer_
= get_empty_string();
44 void set_size_and_add_null_character(size_t size
) {
46 if (buffer_
!= get_empty_string())
47 buffer_
[size_
] = NULL_CHARACTER
;
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();
57 LIBC_INLINE
string(const char *cstr
, size_t count
) {
59 inline_memcpy((void *)buffer_
, (const void *)cstr
, count
);
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
) {
65 inline_memset((void *)buffer_
, value
, size_
);
68 LIBC_INLINE string
&operator=(const string
&other
) {
70 return (*this) += other
;
73 LIBC_INLINE string
&operator=(string
&&other
) {
74 buffer_
= other
.buffer_
;
76 capacity_
= other
.capacity_
;
77 other
.reset_no_deallocate();
81 LIBC_INLINE
~string() {
82 if (buffer_
!= get_empty_string())
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; }
90 LIBC_INLINE
constexpr const char *data() const { return buffer_
; }
91 LIBC_INLINE
char *data() { return buffer_
; }
93 LIBC_INLINE
constexpr const char *begin() const { return data(); }
94 LIBC_INLINE
char *begin() { return data(); }
96 LIBC_INLINE
constexpr const char *end() const { return data() + size_
; }
97 LIBC_INLINE
char *end() { return data() + size_
; }
99 LIBC_INLINE
constexpr const char &front() const { return data()[0]; }
100 LIBC_INLINE
char &front() { return data()[0]; }
102 LIBC_INLINE
constexpr const char &back() const { return data()[size_
- 1]; }
103 LIBC_INLINE
char &back() { return data()[size_
- 1]; }
105 LIBC_INLINE
constexpr const char &operator[](size_t index
) const {
106 return data()[index
];
108 LIBC_INLINE
char &operator[](size_t index
) { return data()[index
]; }
110 LIBC_INLINE
const char *c_str() const { return data(); }
112 LIBC_INLINE
operator string_view() const {
113 return string_view(buffer_
, size_
);
116 LIBC_INLINE
void reserve(size_t new_capacity
) {
117 ++new_capacity
; // Accounting for the terminating '\0'
118 if (new_capacity
<= capacity_
)
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_
,
127 buffer_
= static_cast<char *>(Ptr
);
128 capacity_
= new_capacity
;
130 __builtin_unreachable(); // out of memory
134 LIBC_INLINE
void resize(size_t size
) {
135 if (size
> capacity_
) {
137 const size_t size_extension
= size
- size_
;
138 inline_memset(data() + size_
, '\0', size_extension
);
140 set_size_and_add_null_character(size
);
143 LIBC_INLINE string
&operator+=(const string
&rhs
) {
144 const size_t new_size
= size_
+ rhs
.size();
146 inline_memcpy(buffer_
+ size_
, rhs
.data(), rhs
.size());
147 set_size_and_add_null_character(new_size
);
151 LIBC_INLINE string
&operator+=(const char c
) {
152 const size_t new_size
= size_
+ 1;
155 set_size_and_add_null_character(new_size
);
160 LIBC_INLINE
bool operator==(const string
&lhs
, const string
&rhs
) {
161 return string_view(lhs
) == string_view(rhs
);
163 LIBC_INLINE
bool operator!=(const string
&lhs
, const string
&rhs
) {
164 return string_view(lhs
) != string_view(rhs
);
166 LIBC_INLINE
bool operator<(const string
&lhs
, const string
&rhs
) {
167 return string_view(lhs
) < string_view(rhs
);
169 LIBC_INLINE
bool operator<=(const string
&lhs
, const string
&rhs
) {
170 return string_view(lhs
) <= string_view(rhs
);
172 LIBC_INLINE
bool operator>(const string
&lhs
, const string
&rhs
) {
173 return string_view(lhs
) > string_view(rhs
);
175 LIBC_INLINE
bool operator>=(const string
&lhs
, const string
&rhs
) {
176 return string_view(lhs
) >= string_view(rhs
);
179 LIBC_INLINE string
operator+(const string
&lhs
, const string
&rhs
) {
183 LIBC_INLINE string
operator+(const string
&lhs
, const char *rhs
) {
184 return lhs
+ string(rhs
);
186 LIBC_INLINE string
operator+(const char *lhs
, const string
&rhs
) {
187 return string(lhs
) + rhs
;
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());
197 } // namespace internal
199 LIBC_INLINE string
to_string(int value
) {
200 return internal::to_dec_string
<int>(value
);
202 LIBC_INLINE string
to_string(long value
) {
203 return internal::to_dec_string
<long>(value
);
205 LIBC_INLINE string
to_string(long long value
) {
206 return internal::to_dec_string
<long long>(value
);
208 LIBC_INLINE string
to_string(unsigned value
) {
209 return internal::to_dec_string
<unsigned>(value
);
211 LIBC_INLINE string
to_string(unsigned long value
) {
212 return internal::to_dec_string
<unsigned long>(value
);
214 LIBC_INLINE string
to_string(unsigned long long value
) {
215 return internal::to_dec_string
<unsigned long long>(value
);
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);
224 } // namespace __llvm_libc
226 #endif // LLVM_LIBC_SRC_SUPPORT_CPP_STRING_H