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