• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/inline_memcpy.h"
15 #include "src/string/memory_utils/inline_memset.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 LIBC_NAMESPACE {
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';
get_empty_string()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 
reset_no_deallocate()38   constexpr void reset_no_deallocate() {
39     buffer_ = get_empty_string();
40     size_ = 0;
41     capacity_ = 0;
42   }
43 
set_size_and_add_null_character(size_t size)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:
string()51   LIBC_INLINE constexpr string() {}
string(const string & other)52   LIBC_INLINE string(const string &other) { this->operator+=(other); }
string(string && other)53   LIBC_INLINE constexpr string(string &&other)
54       : buffer_(other.buffer_), size_(other.size_), capacity_(other.capacity_) {
55     other.reset_no_deallocate();
56   }
string(const char * cstr,size_t count)57   LIBC_INLINE string(const char *cstr, size_t count) {
58     resize(count);
59     inline_memcpy(buffer_, cstr, count);
60   }
string(const string_view & view)61   LIBC_INLINE string(const string_view &view)
62       : string(view.data(), view.size()) {}
string(const char * cstr)63   LIBC_INLINE string(const char *cstr)
64       : string(cstr, ::LIBC_NAMESPACE::internal::string_length(cstr)) {}
string(size_t size_,char value)65   LIBC_INLINE string(size_t size_, char value) {
66     resize(size_);
67     inline_memset((void *)buffer_, value, size_);
68   }
69 
70   LIBC_INLINE string &operator=(const string &other) {
71     resize(0);
72     return (*this) += other;
73   }
74 
75   LIBC_INLINE string &operator=(string &&other) {
76     buffer_ = other.buffer_;
77     size_ = other.size_;
78     capacity_ = other.capacity_;
79     other.reset_no_deallocate();
80     return *this;
81   }
82 
83   LIBC_INLINE string &operator=(const string_view &view) {
84     return *this = string(view);
85   }
86 
~string()87   LIBC_INLINE ~string() {
88     if (buffer_ != get_empty_string())
89       ::free(buffer_);
90   }
91 
capacity()92   LIBC_INLINE constexpr size_t capacity() const { return capacity_; }
size()93   LIBC_INLINE constexpr size_t size() const { return size_; }
empty()94   LIBC_INLINE constexpr bool empty() const { return size_ == 0; }
95 
data()96   LIBC_INLINE constexpr const char *data() const { return buffer_; }
data()97   LIBC_INLINE char *data() { return buffer_; }
98 
begin()99   LIBC_INLINE constexpr const char *begin() const { return data(); }
begin()100   LIBC_INLINE char *begin() { return data(); }
101 
end()102   LIBC_INLINE constexpr const char *end() const { return data() + size_; }
end()103   LIBC_INLINE char *end() { return data() + size_; }
104 
front()105   LIBC_INLINE constexpr const char &front() const { return data()[0]; }
front()106   LIBC_INLINE char &front() { return data()[0]; }
107 
back()108   LIBC_INLINE constexpr const char &back() const { return data()[size_ - 1]; }
back()109   LIBC_INLINE char &back() { return data()[size_ - 1]; }
110 
111   LIBC_INLINE constexpr const char &operator[](size_t index) const {
112     return data()[index];
113   }
114   LIBC_INLINE char &operator[](size_t index) { return data()[index]; }
115 
c_str()116   LIBC_INLINE const char *c_str() const { return data(); }
117 
string_view()118   LIBC_INLINE operator string_view() const {
119     return string_view(buffer_, size_);
120   }
121 
reserve(size_t new_capacity)122   LIBC_INLINE void reserve(size_t new_capacity) {
123     ++new_capacity; // Accounting for the terminating '\0'
124     if (new_capacity <= capacity_)
125       return;
126     // We extend the capacity to amortize buffer_ reallocations.
127     // We choose to augment the value by 11 / 8, this is about +40% and division
128     // by 8 is cheap. We guard the extension so the operation doesn't overflow.
129     if (new_capacity < SIZE_MAX / 11)
130       new_capacity = new_capacity * 11 / 8;
131     if (void *Ptr = ::realloc(buffer_ == get_empty_string() ? nullptr : buffer_,
132                               new_capacity)) {
133       buffer_ = static_cast<char *>(Ptr);
134       capacity_ = new_capacity;
135     } else {
136       __builtin_unreachable(); // out of memory
137     }
138   }
139 
resize(size_t size)140   LIBC_INLINE void resize(size_t size) {
141     if (size > capacity_) {
142       reserve(size);
143       const size_t size_extension = size - size_;
144       inline_memset(data() + size_, '\0', size_extension);
145     }
146     set_size_and_add_null_character(size);
147   }
148 
149   LIBC_INLINE string &operator+=(const string &rhs) {
150     const size_t new_size = size_ + rhs.size();
151     reserve(new_size);
152     inline_memcpy(buffer_ + size_, rhs.data(), rhs.size());
153     set_size_and_add_null_character(new_size);
154     return *this;
155   }
156 
157   LIBC_INLINE string &operator+=(const char c) {
158     const size_t new_size = size_ + 1;
159     reserve(new_size);
160     buffer_[size_] = c;
161     set_size_and_add_null_character(new_size);
162     return *this;
163   }
164 };
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 LIBC_INLINE bool operator>(const string &lhs, const string &rhs) {
179   return string_view(lhs) > string_view(rhs);
180 }
181 LIBC_INLINE bool operator>=(const string &lhs, const string &rhs) {
182   return string_view(lhs) >= string_view(rhs);
183 }
184 
185 LIBC_INLINE string operator+(const string &lhs, const string &rhs) {
186   string Tmp(lhs);
187   return Tmp += rhs;
188 }
189 LIBC_INLINE string operator+(const string &lhs, const char *rhs) {
190   return lhs + string(rhs);
191 }
192 LIBC_INLINE string operator+(const char *lhs, const string &rhs) {
193   return string(lhs) + rhs;
194 }
195 
196 namespace internal {
to_dec_string(T value)197 template <typename T> string to_dec_string(T value) {
198   const IntegerToString<T> buffer(value);
199   return buffer.view();
200 }
201 } // namespace internal
202 
to_string(int value)203 LIBC_INLINE string to_string(int value) {
204   return internal::to_dec_string<int>(value);
205 }
to_string(long value)206 LIBC_INLINE string to_string(long value) {
207   return internal::to_dec_string<long>(value);
208 }
to_string(long long value)209 LIBC_INLINE string to_string(long long value) {
210   return internal::to_dec_string<long long>(value);
211 }
to_string(unsigned value)212 LIBC_INLINE string to_string(unsigned value) {
213   return internal::to_dec_string<unsigned>(value);
214 }
to_string(unsigned long value)215 LIBC_INLINE string to_string(unsigned long value) {
216   return internal::to_dec_string<unsigned long>(value);
217 }
to_string(unsigned long long value)218 LIBC_INLINE string to_string(unsigned long long value) {
219   return internal::to_dec_string<unsigned long long>(value);
220 }
221 
222 // TODO: Support floating point
223 // LIBC_INLINE string to_string(float value);
224 // LIBC_INLINE string to_string(double value);
225 // LIBC_INLINE string to_string(long double value);
226 
227 } // namespace cpp
228 } // namespace LIBC_NAMESPACE
229 
230 #endif // LLVM_LIBC_SRC___SUPPORT_CPP_STRING_H
231