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