userver: userver/utils/small_string.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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};