userver: userver/utils/small_string.hpp Source File
Loading...
Searching...
No Matches
small_string.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/utils/small_string.hpp
4/// @brief @copybrief utils::SmallString
5
6#include <cstddef>
7#include <functional>
8#include <stdexcept>
9#include <string>
10
11#include <boost/container/small_vector.hpp>
12
13#include <userver/utils/assert.hpp>
14
15USERVER_NAMESPACE_BEGIN
16
17namespace utils {
18
19/// @ingroup userver_universal userver_containers
20///
21/// @brief An alternative to std::string with a custom SSO (small string
22/// optimization) container size. Unlike std::string, SmallString is not
23/// null-terminated thus it has no c_str(), data() returns a not null-terminated
24/// buffer.
25template <std::size_t N>
26class SmallString final {
27 using Container = boost::container::small_vector<char, N>;
28
29 public:
30 /// @brief Create empty string.
31 SmallString() = default;
32
33 /// @brief Create a string from another one.
34 SmallString(const SmallString<N>&) = default;
35
36 /// @brief Create a string from another one.
37 explicit SmallString(SmallString<N>&&) noexcept = default;
38
39 /// @brief Create a string from std::string_view.
40 explicit SmallString(std::string_view sv);
41
42 /// @brief Assign the value of other string_view to this string.
43 SmallString& operator=(std::string_view sv);
44
45 /// @brief Assign the value of other string to this string.
46 SmallString& operator=(const SmallString&) = default;
47
48 /// @brief Assign the value of other string to this string.
49 SmallString& operator=(SmallString&&) noexcept = default;
50
51 /// @brief Convert string to a std::string_view.
52 operator std::string_view() const;
53
54 /// @brief Read-only subscript access to the data contained in the string.
55 const char& operator[](std::size_t pos) const;
56
57 /// @brief Subscript access to the data contained in the string.
58 char& operator[](std::size_t pos);
59
60 /// @brief Provides access to the data contained in the string.
61 const char& at(std::size_t pos) const;
62
63 /// @brief Provides access to the data contained in the string.
64 char& at(std::size_t pos);
65
66 using iterator = typename Container::iterator;
67
68 using const_iterator = typename Container::const_iterator;
69
70 iterator begin() noexcept;
71 const_iterator begin() const noexcept;
72
73 iterator end() noexcept;
74 const_iterator end() const noexcept;
75
76 /// @brief Get string size.
77 std::size_t size() const noexcept;
78
79 /// @brief Get pointer to data.
80 /// @warning The buffer is not null-terminated.
81 const char* data() const noexcept;
82
83 /// @brief Get pointer to data.
84 /// @warning The buffer is not null-terminated.
85 char* data() noexcept;
86
87 /// @brief Resize the string. If its length is increased,
88 /// fill new chars with %c.
89 void resize(std::size_t n, char c);
90
91 /// @brief Resize the string. Use op to write into the string and replace a
92 /// sequence of characters
93 template <class Operation>
94 void resize_and_overwrite(std::size_t size, Operation op);
95
96 /// @brief Shrink the string's size to fit all contents
97 void shrink_to_fit();
98
99 /// @brief Get current capacity.
100 std::size_t capacity() const noexcept;
101
102 /// @brief Reserve to %n bytes.
103 void reserve(std::size_t n);
104
105 /// @brief Clear the string.
106 void clear() noexcept;
107
108 /// @brief Is the string empty?
109 bool empty() const noexcept;
110
111 /// @brief Get a reference to the first character.
112 char& front();
113
114 /// @brief Get a reference to the first character.
115 const char& front() const;
116
117 /// @brief Get a reference to the last character.
118 char& back();
119
120 /// @brief Get a reference to the last character.
121 const char& back() const;
122
123 /// @brief Append a character to the string.
124 void push_back(char c);
125
126 /// @brief Append contents of a string_view to the string.
127 void append(std::string_view str);
128
129 /// @brief Remove the last character from the string.
130 void pop_back();
131
132 private:
133 boost::container::small_vector<char, N> data_;
134};
135
136template <std::size_t N>
137SmallString<N>::SmallString(std::string_view sv)
138 : data_(sv.begin(), sv.end()) {}
139
140template <std::size_t N>
141SmallString<N>::operator std::string_view() const {
142 return std::string_view{data_.data(), data_.size()};
143}
144
145template <std::size_t N>
146SmallString<N>& SmallString<N>::operator=(std::string_view sv) {
147 data_ = {sv.begin(), sv.end()};
148 return *this;
149}
150
151template <std::size_t N>
152bool operator==(const SmallString<N>& str, std::string_view sv) {
153 return std::string_view{str} == sv;
154}
155
156template <std::size_t N>
157bool operator==(std::string_view sv, const SmallString<N>& str) {
158 return std::string_view{str} == sv;
159}
160
161template <std::size_t N>
162bool operator==(const SmallString<N>& str1, const SmallString<N>& str2) {
163 return std::string_view{str1} == std::string_view{str2};
164}
165
166template <std::size_t N>
167bool operator!=(const SmallString<N>& str1, const SmallString<N>& str2) {
168 return !(str1 == str2);
169}
170
171template <std::size_t N>
172const char& SmallString<N>::operator[](std::size_t pos) const {
173 return data_[pos];
174}
175
176template <std::size_t N>
177char& SmallString<N>::operator[](std::size_t pos) {
178 return data_[pos];
179}
180
181template <std::size_t N>
182const char& SmallString<N>::at(std::size_t pos) const {
183 if (size() <= pos) throw std::out_of_range("at");
184 return data_[pos];
185}
186
187template <std::size_t N>
188char& SmallString<N>::at(std::size_t pos) {
189 if (size() <= pos) throw std::out_of_range("at");
190 return data_[pos];
191}
192
193template <std::size_t N>
194typename SmallString<N>::iterator SmallString<N>::begin() noexcept {
195 return {data_.begin()};
196}
197
198template <std::size_t N>
199typename SmallString<N>::const_iterator SmallString<N>::begin() const noexcept {
200 return {data_.begin()};
201}
202
203template <std::size_t N>
204typename SmallString<N>::iterator SmallString<N>::end() noexcept {
205 return {data_.end()};
206}
207
208template <std::size_t N>
209typename SmallString<N>::const_iterator SmallString<N>::end() const noexcept {
210 return {data_.end()};
211}
212
213template <std::size_t N>
214std::size_t SmallString<N>::size() const noexcept {
215 return data_.size();
216}
217
218template <std::size_t N>
219const char* SmallString<N>::data() const noexcept {
220 return data_.data();
221}
222
223template <std::size_t N>
224char* SmallString<N>::data() noexcept {
225 return data_.data();
226}
227
228template <std::size_t N>
229bool SmallString<N>::empty() const noexcept {
230 return data_.empty();
231}
232
233template <std::size_t N>
234char& SmallString<N>::front() {
235 return data_.front();
236}
237
238template <std::size_t N>
239const char& SmallString<N>::front() const {
240 return data_.front();
241}
242
243template <std::size_t N>
244char& SmallString<N>::back() {
245 return data_.back();
246}
247
248template <std::size_t N>
249const char& SmallString<N>::back() const {
250 return data_.back();
251}
252
253template <std::size_t N>
254void SmallString<N>::push_back(char c) {
255 data_.push_back(c);
256}
257
258template <std::size_t N>
259void SmallString<N>::append(std::string_view str) {
260 std::size_t old_size = data_.size();
261 data_.insert(data_.begin() + old_size, str.begin(), str.end());
262}
263
264template <std::size_t N>
265void SmallString<N>::pop_back() {
266 data_.pop_back();
267}
268
269template <std::size_t N>
270void SmallString<N>::resize(std::size_t n, char c) {
271 data_.resize(n, c);
272}
273
274template <std::size_t N>
275template <class Operation>
276void SmallString<N>::resize_and_overwrite(std::size_t size, Operation op) {
277 data_.resize(size, boost::container::default_init);
278 data_.resize(std::move(op)(data_.data(), size),
279 boost::container::default_init);
280 UASSERT(data_.size() <= size);
281}
282
283template <std::size_t N>
284void SmallString<N>::shrink_to_fit() {
285 data_.shrink_to_fit();
286}
287
288template <std::size_t N>
289std::size_t SmallString<N>::capacity() const noexcept {
290 return data_.capacity();
291}
292
293template <std::size_t N>
294void SmallString<N>::reserve(std::size_t n) {
295 return data_.reserve(n);
296}
297
298template <std::size_t N>
299void SmallString<N>::clear() noexcept {
300 data_.clear();
301}
302
303} // namespace utils
304
305USERVER_NAMESPACE_END
306
307template <std::size_t N>
308struct std::hash<USERVER_NAMESPACE::utils::SmallString<N>> {
309 std::size_t operator()(
310 const USERVER_NAMESPACE::utils::SmallString<N>& s) const noexcept {
311 return std::hash<std::string_view>{}(std::string_view{s});
312 }
313};