[libc][NFC] Move aligned access implementations to separate header
[llvm-project.git] / libc / src / __support / CPP / string.h
blobfa73d536b3c4b99c51e867b65776f38cabdc64b6
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 //===----------------------------------------------------------------------===//
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 {
22 namespace cpp {
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);
34 char *buffer_ = get_empty_string();
35 size_t size_ = 0;
36 size_t capacity_ = 0;
38 constexpr void reset_no_deallocate() {
39 buffer_ = get_empty_string();
40 size_ = 0;
41 capacity_ = 0;
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;
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();
57 LIBC_INLINE string(const char *cstr, size_t count) {
58 resize(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) {
64 resize(size_);
65 inline_memset((void *)buffer_, value, size_);
68 LIBC_INLINE string &operator=(const string &other) {
69 resize(0);
70 return (*this) += other;
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;
81 LIBC_INLINE ~string() {
82 if (buffer_ != get_empty_string())
83 ::free(buffer_);
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_)
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
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);
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();
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;
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;
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) {
180 string Tmp(lhs);
181 return Tmp += 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;
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());
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);
223 } // namespace cpp
224 } // namespace __llvm_libc
226 #endif // LLVM_LIBC_SRC_SUPPORT_CPP_STRING_H