1 // This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
2 // the main distribution directory for license terms and copyright or visit
3 // https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
4
5 #pragma once
6
7 #include <cstddef>
8 #include <cstring>
9 #include <iosfwd>
10 #include <iterator>
11 #include <limits>
12 #include <string>
13 #include <type_traits>
14
15 #include "caf/detail/comparable.hpp"
16 #include "caf/detail/core_export.hpp"
17
18 namespace caf {
19
20 namespace detail {
21
22 // Catches `std::string`, `std::string_view` and all classes mimicking those,
23 // but not `std::vector<char>` or other buffers.
24 template <class T>
25 struct is_string_like {
26 // SFINAE checks.
27 template <class U>
28 static bool sfinae(
29 const U* x,
30 // check if `x->data()` returns const char*
31 std::enable_if_t<
32 std::is_same<const char*, decltype(x->data())>::value>* = nullptr,
33 // check if `x->size()` returns an integer
34 std::enable_if_t<std::is_integral<decltype(x->size())>::value>* = nullptr,
35 // check if `x->find('?', 0)` is well-formed and returns an integer
36 // (distinguishes vectors from strings)
37 std::enable_if_t<
38 std::is_integral<decltype(x->find('?', 0))>::value>* = nullptr);
39
40 // SFINAE fallback.
41 static void sfinae(void*);
42
43 // Result of SFINAE test.
44 using result_type
45 = decltype(sfinae(static_cast<typename std::decay<T>::type*>(nullptr)));
46
47 // Trait result.
48 static constexpr bool value = std::is_same<bool, result_type>::value;
49 };
50
51 } // namespace detail
52
53 /// Drop-in replacement for C++17 std::string_view.
54 class CAF_CORE_EXPORT string_view : detail::comparable<string_view> {
55 public:
56 // -- member types -----------------------------------------------------------
57
58 using value_type = char;
59 using pointer = value_type*;
60 using const_pointer = const value_type*;
61 using reference = value_type&;
62 using const_reference = const value_type&;
63 using const_iterator = const_pointer;
64 using iterator = const_iterator;
65 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
66 using reverse_iterator = const_reverse_iterator;
67 using size_type = size_t;
68 using difference_type = ptrdiff_t;
69
70 // -- constants --------------------------------------------------------------
71
72 static constexpr size_type npos = std::numeric_limits<size_type>::max();
73
74 // -- constructors, destructors, and assignment operators --------------------
75
string_view()76 constexpr string_view() noexcept : data_(nullptr), size_(0) {
77 // nop
78 }
79
string_view(const char * cstr,size_t length)80 constexpr string_view(const char* cstr, size_t length) noexcept
81 : data_(cstr), size_(length) {
82 // nop
83 }
84
string_view(iterator first,iterator last)85 constexpr string_view(iterator first, iterator last) noexcept
86 : data_(first), size_(static_cast<size_t>(last - first)) {
87 // nop
88 }
89
90 #ifdef CAF_GCC
string_view(const char * cstr)91 constexpr string_view(const char* cstr) noexcept
92 : data_(cstr), size_(strlen(cstr)) {
93 // nop
94 }
95 #else
96 template <size_t N>
string_view(const char (& cstr)[N])97 constexpr string_view(const char (&cstr)[N]) noexcept
98 : data_(cstr), size_(N - 1) {
99 // nop
100 }
101 #endif
102
103 constexpr string_view(const string_view&) noexcept = default;
104
105 template <class T, class = typename std::enable_if<
106 detail::is_string_like<T>::value>::type>
string_view(const T & str)107 constexpr string_view(const T& str) noexcept
108 : data_(str.data()), size_(str.size()) {
109 // nop
110 }
111
112 string_view& operator=(const string_view&) noexcept = default;
113
114 // -- capacity ---------------------------------------------------------------
115
size() const116 constexpr size_type size() const noexcept {
117 return size_;
118 }
119
length() const120 constexpr size_type length() const noexcept {
121 return size_;
122 }
123
max_size() const124 constexpr size_type max_size() const noexcept {
125 return std::numeric_limits<size_type>::max();
126 }
127
empty() const128 constexpr bool empty() const noexcept {
129 return size_ == 0;
130 }
131
132 // -- iterator access --------------------------------------------------------
133
begin() const134 constexpr const_iterator begin() const noexcept {
135 return data_;
136 }
137
end() const138 constexpr const_iterator end() const noexcept {
139 return data_ + size_;
140 }
141
cbegin() const142 constexpr const_iterator cbegin() const noexcept {
143 return begin();
144 }
145
cend() const146 constexpr const_iterator cend() const noexcept {
147 return end();
148 }
149
150 const_reverse_iterator rbegin() const noexcept;
151
152 const_reverse_iterator rend() const noexcept;
153
154 const_reverse_iterator crbegin() const noexcept;
155
156 const_reverse_iterator crend() const noexcept;
157
158 // -- element access ---------------------------------------------------------
159
operator [](size_type pos) const160 constexpr const_reference operator[](size_type pos) const {
161 return data_[pos];
162 }
163
164 const_reference at(size_type pos) const;
165
front() const166 constexpr const_reference front() const {
167 return *data_;
168 }
169
back() const170 constexpr const_reference back() const {
171 return data_[size_ - 1];
172 }
173
data() const174 constexpr const_pointer data() const noexcept {
175 return data_;
176 }
177
178 // -- modifiers --------------------------------------------------------------
179
180 void remove_prefix(size_type n);
181
182 void remove_suffix(size_type n);
183
184 void assign(const_pointer data, size_type len);
185
186 // -- algorithms -------------------------------------------------------------
187
188 size_type copy(pointer dest, size_type n, size_type pos = 0) const;
189
190 string_view substr(size_type pos = 0, size_type n = npos) const noexcept;
191
192 int compare(string_view s) const noexcept;
193
194 int compare(size_type pos1, size_type n1, string_view str) const noexcept;
195
196 int compare(size_type pos1, size_type n1, string_view str, size_type pos2,
197 size_type n2) const noexcept;
198
199 int compare(const_pointer str) const noexcept;
200
201 int compare(size_type pos, size_type n, const_pointer str) const noexcept;
202
203 int compare(size_type pos1, size_type n1, const_pointer s, size_type n2) const
204 noexcept;
205
206 size_type find(string_view str, size_type pos = 0) const noexcept;
207
208 size_type find(value_type ch, size_type pos = 0) const noexcept;
209
210 size_type find(const_pointer str, size_type pos, size_type n) const noexcept;
211
212 size_type find(const_pointer str, size_type pos = 0) const noexcept;
213
214 size_type rfind(string_view str, size_type pos = npos) const noexcept;
215
216 size_type rfind(value_type ch, size_type pos = npos) const noexcept;
217
218 size_type rfind(const_pointer str, size_type pos, size_type n) const noexcept;
219
220 size_type rfind(const_pointer str, size_type pos = npos) const noexcept;
221
222 size_type find_first_of(string_view str, size_type pos = 0) const noexcept;
223
224 size_type find_first_of(value_type ch, size_type pos = 0) const noexcept;
225
226 size_type find_first_of(const_pointer str, size_type pos, size_type n) const
227 noexcept;
228
229 size_type find_first_of(const_pointer str, size_type pos = 0) const noexcept;
230
231 size_type find_last_of(string_view str, size_type pos = npos) const noexcept;
232
233 size_type find_last_of(value_type ch, size_type pos = npos) const noexcept;
234
235 size_type find_last_of(const_pointer str, size_type pos, size_type n) const
236 noexcept;
237
238 size_type find_last_of(const_pointer str, size_type pos = npos) const
239 noexcept;
240
241 size_type find_first_not_of(string_view str, size_type pos = 0) const
242 noexcept;
243
244 size_type find_first_not_of(value_type ch, size_type pos = 0) const noexcept;
245
246 size_type find_first_not_of(const_pointer str, size_type pos,
247 size_type n) const noexcept;
248
249 size_type find_first_not_of(const_pointer str, size_type pos = 0) const
250 noexcept;
251
252 size_type find_last_not_of(string_view str, size_type pos = npos) const
253 noexcept;
254
255 size_type find_last_not_of(value_type ch, size_type pos = npos) const
256 noexcept;
257
258 size_type find_last_not_of(const_pointer str, size_type pos,
259 size_type n) const noexcept;
260
261 size_type find_last_not_of(const_pointer str, size_type pos = npos) const
262 noexcept;
263
264 private:
265 const char* data_;
266 size_t size_;
267 };
268
269 /// @relates string_view
to_string(string_view x)270 inline std::string to_string(string_view x) {
271 return std::string{x.begin(), x.end()};
272 }
273
274 } // namespace caf
275
276 namespace caf::literals {
277
operator ""_sv(const char * cstr,size_t len)278 constexpr string_view operator""_sv(const char* cstr, size_t len) {
279 return {cstr, len};
280 }
281
282 } // namespace caf::literals
283
284 namespace std {
285
286 CAF_CORE_EXPORT std::ostream& operator<<(std::ostream& out, caf::string_view);
287
288 } // namespace std
289