Warning: This file is not a C or C++ file. It does not have highlighting.

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

Warning: This file is not a C or C++ file. It does not have highlighting.

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of libc/src/__support/CPP/string.h