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
29public:
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
132private:
133 boost::container::small_vector<char, N> data_;
134};
135
136template <std::size_t N>
137SmallString<N>::SmallString(std::string_view sv) : data_(sv.begin(), sv.end()) {}
138
139template <std::size_t N>
141 return std::string_view{data_.data(), data_.size()};
142}
143
144template <std::size_t N>
146 data_ = {sv.begin(), sv.end()};
147 return *this;
148}
149
150template <std::size_t N>
151bool operator==(const SmallString<N>& str, std::string_view sv) {
152 return std::string_view{str} == sv;
153}
154
155template <std::size_t N>
156bool operator==(std::string_view sv, const SmallString<N>& str) {
157 return std::string_view{str} == sv;
158}
159
160template <std::size_t N>
161bool operator==(const SmallString<N>& str1, const SmallString<N>& str2) {
162 return std::string_view{str1} == std::string_view{str2};
163}
164
165template <std::size_t N>
166bool operator!=(const SmallString<N>& str1, const SmallString<N>& str2) {
167 return !(str1 == str2);
168}
169
170template <std::size_t N>
171const char& SmallString<N>::operator[](std::size_t pos) const {
172 return data_[pos];
173}
174
175template <std::size_t N>
177 return data_[pos];
178}
179
180template <std::size_t N>
181const char& SmallString<N>::at(std::size_t pos) const {
182 if (size() <= pos) throw std::out_of_range("at");
183 return data_[pos];
184}
185
186template <std::size_t N>
188 if (size() <= pos) throw std::out_of_range("at");
189 return data_[pos];
190}
191
192template <std::size_t N>
193typename SmallString<N>::iterator SmallString<N>::begin() noexcept {
194 return {data_.begin()};
195}
196
197template <std::size_t N>
198typename SmallString<N>::const_iterator SmallString<N>::begin() const noexcept {
199 return {data_.begin()};
200}
201
202template <std::size_t N>
203typename SmallString<N>::iterator SmallString<N>::end() noexcept {
204 return {data_.end()};
205}
206
207template <std::size_t N>
208typename SmallString<N>::const_iterator SmallString<N>::end() const noexcept {
209 return {data_.end()};
210}
211
212template <std::size_t N>
213std::size_t SmallString<N>::size() const noexcept {
214 return data_.size();
215}
216
217template <std::size_t N>
218const char* SmallString<N>::data() const noexcept {
219 return data_.data();
220}
221
222template <std::size_t N>
223char* SmallString<N>::data() noexcept {
224 return data_.data();
225}
226
227template <std::size_t N>
228bool SmallString<N>::empty() const noexcept {
229 return data_.empty();
230}
231
232template <std::size_t N>
233char& SmallString<N>::front() {
234 return data_.front();
235}
236
237template <std::size_t N>
238const char& SmallString<N>::front() const {
239 return data_.front();
240}
241
242template <std::size_t N>
243char& SmallString<N>::back() {
244 return data_.back();
245}
246
247template <std::size_t N>
248const char& SmallString<N>::back() const {
249 return data_.back();
250}
251
252template <std::size_t N>
253void SmallString<N>::push_back(char c) {
255}
256
257template <std::size_t N>
261}
262
263template <std::size_t N>
265 data_.pop_back();
266}
267
268template <std::size_t N>
269void SmallString<N>::resize(std::size_t n, char c) {
270 data_.resize(n, c);
271}
272
273template <std::size_t N>
274template <class Operation>
278 UASSERT(data_.size() <= size);
279}
280
281template <std::size_t N>
284}
285
286template <std::size_t N>
287std::size_t SmallString<N>::capacity() const noexcept {
288 return data_.capacity();
289}
290
291template <std::size_t N>
293 return data_.reserve(n);
294}
295
296template <std::size_t N>
297void SmallString<N>::clear() noexcept {
298 data_.clear();
299}
300
301} // namespace utils
302
303USERVER_NAMESPACE_END
304
305template <std::size_t N>
306struct std::hash<USERVER_NAMESPACE::utils::SmallString<N>> {
307 std::size_t operator()(const USERVER_NAMESPACE::utils::SmallString<N>& s) const noexcept {
308 return std::hash<std::string_view>{}(std::string_view{s});
309 }
310};