JASL  [1.2.0]-2018-09-11
jasl_string_view.hpp
Go to the documentation of this file.
1 // JASL: For more information see https://github.com/matepek/jasl
2 //
3 // Copyright (c) 2018 Mate Pek
4 //
5 // This code is licensed under the MIT License (MIT).
6 
9 #pragma once
10 
11 #include <algorithm>
12 #include <iterator>
13 #include <stdexcept>
14 #include <string>
15 #include <type_traits>
16 
18 #include "jasl/jasl_internal/jasl_feature_test_macro.hpp"
19 
20 namespace jasl {
21 namespace nonstd {
22 
23 template <typename CharT, typename Traits = std::char_traits<CharT>>
25 
30 
31 } // namespace nonstd
32 } // namespace jasl
33 
34 #if defined(JASL_USE_JASL_STRING_VIEW_AS_BASE) && \
35  defined(JASL_USE_STD_STRING_VIEW_AS_BASE)
36 # error "Both defines cannot be used at the same time."
37 #elif defined(JASL_USE_JASL_STRING_VIEW_AS_BASE)
38 # define JASL_INNER_USE_STD_STRING_VIEW_AS_BASE 0
39 #elif defined(JASL_USE_STD_STRING_VIEW_AS_BASE)
40 # define JASL_INNER_USE_STD_STRING_VIEW_AS_BASE 1
41 #elif !defined(JASL_USE_JASL_STRING_VIEW_AS_BASE) && \
42  !defined(JASL_USE_STD_STRING_VIEW_AS_BASE)
43 /* fallback logic */
44 # if defined(JASL_cpp_lib_string_view)
45 # define JASL_INNER_USE_STD_STRING_VIEW_AS_BASE 1
46 # else
47 # define JASL_INNER_USE_STD_STRING_VIEW_AS_BASE 0
48 # endif
49 #else
50 # error "Something is really wrong."
51 #endif
52 
53 #if JASL_INNER_USE_STD_STRING_VIEW_AS_BASE
54 
55 # include <string_view>
56 
57 namespace jasl {
58 template <typename CharT, typename Traits = std::char_traits<CharT>>
59 using basic_string_view = std::basic_string_view<CharT, Traits>;
60 } // namespace jasl
61 
62 #else // JASL_INNER_USE_STD_STRING_VIEW_AS_BASE
63 
64 namespace jasl {
75 template <typename CharT, typename Traits = std::char_traits<CharT>>
77 } // namespace jasl
78 
79 #endif // JASL_INNER_USE_STD_STRING_VIEW_AS_BASE
80 
81 namespace jasl {
82 typedef basic_string_view<char> string_view;
83 typedef basic_string_view<wchar_t> wstring_view;
84 typedef basic_string_view<char16_t> u16string_view;
85 typedef basic_string_view<char32_t> u32string_view;
86 } // namespace jasl
87 
88 namespace jasl {
89 namespace nonstd {
90 
99 template <typename CharT, typename Traits>
100 class basic_string_view {
101  const CharT* _ptr;
102  size_t _size;
103 
104  public:
105  // types
106  typedef Traits traits_type;
107  typedef CharT value_type;
108  typedef CharT* pointer;
109  typedef const CharT* const_pointer;
110  typedef CharT& reference;
111  typedef const CharT& const_reference;
112  typedef const_pointer const_iterator;
113  typedef const_iterator iterator;
114  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
115  typedef const_reverse_iterator reverse_iterator;
116  typedef size_t size_type;
117  typedef std::ptrdiff_t difference_type;
118  static constexpr size_type npos = static_cast<size_type>(-1);
119 
120  public:
121  constexpr basic_string_view() noexcept : _ptr(nullptr), _size(0) {}
122 
123  constexpr basic_string_view(const CharT* ptr, size_type size) noexcept
124  : _ptr(ptr), _size(size) {}
125 
126  constexpr basic_string_view(const basic_string_view& other) noexcept
127  : _ptr(other._ptr), _size(other._size) {}
128 
129  JASL_CONSTEXPR_CXX14 basic_string_view& operator=(
130  const basic_string_view& other) noexcept {
131  _ptr = other._ptr;
132  _size = other._size;
133  return *this;
134  }
135 
136  ~basic_string_view() noexcept = default;
137 
138 #if defined(JASL_SUPPORT_STD_TO_JASL)
139 # if defined(JASL_cpp_lib_string_view)
140  template <
141  typename T,
142  typename = typename std::enable_if<
143  std::is_convertible<const T&,
144  std::basic_string_view<CharT, Traits>>::value &&
145  !std::is_convertible<const T&, const CharT*>::value>::type>
146  explicit constexpr basic_string_view(const T& s) noexcept(
147  noexcept(s.data()) && noexcept(s.size())) {
148  std::basic_string_view<CharT, Traits> sv(s);
149  _ptr = sv.data();
150  _size = sv.size();
151  }
152 
153  JASL_CONSTEXPR_CXX14 basic_string_view&
154  operator=(const std::basic_string_view<CharT, Traits>& s) noexcept(
155  noexcept(s.data()) && noexcept(s.size())) {
156  _ptr = s.data();
157  _size = s.size();
158  return *this;
159  }
160 # else
161  template <typename AllocatorT>
162  constexpr basic_string_view(
163  const std::basic_string<CharT, Traits, AllocatorT>&
164  s) noexcept(noexcept(s.data()) && noexcept(s.size()))
165  : _ptr(s.data()), _size(s.size()) {}
166 
167  template <typename AllocatorT>
168  JASL_CONSTEXPR_CXX14 basic_string_view&
169  operator=(const std::basic_string<CharT, Traits, AllocatorT>& s) noexcept(
170  noexcept(s.data()) && noexcept(s.size())) {
171  _ptr = s.data();
172  _size = s.size();
173  return *this;
174  }
175 # endif
176 #endif
177 
178 #if defined(JASL_SUPPORT_JASL_TO_STD)
179 # if defined(JASL_cpp_lib_string_view)
180  operator std::basic_string_view<CharT, Traits>() const noexcept(
181  std::is_nothrow_constructible<std::basic_string_view<CharT, Traits>,
182  const CharT*,
183  size_t>::value) {
184  return std::basic_string_view<CharT, Traits>(_ptr, _size);
185  }
186 # else
187  template <typename AllocatorT>
188  operator std::basic_string<CharT, Traits, AllocatorT>() const
189  noexcept(std::is_nothrow_constructible<
190  std::basic_string<CharT, Traits, AllocatorT>,
191  const CharT*,
192  size_t>::value) {
193  return std::basic_string<CharT, Traits, AllocatorT>(_ptr, _size);
194  }
195 # endif
196 #endif
197 
198  constexpr const_iterator begin() const noexcept { return cbegin(); }
199  constexpr const_iterator end() const noexcept { return cend(); }
200  constexpr const_iterator cbegin() const noexcept { return _ptr; }
201  constexpr const_iterator cend() const noexcept { return _ptr + _size; }
202  constexpr const_reverse_iterator rbegin() const noexcept {
203  return const_reverse_iterator(cend());
204  }
205  constexpr const_reverse_iterator rend() const noexcept {
206  return const_reverse_iterator(cbegin());
207  }
208  constexpr const_reverse_iterator crbegin() const noexcept {
209  return const_reverse_iterator(cend());
210  }
211  constexpr const_reverse_iterator crend() const noexcept {
212  return const_reverse_iterator(cbegin());
213  }
214 
215  constexpr bool empty() const noexcept { return _size == 0; }
216  constexpr const CharT* data() const noexcept { return _ptr; }
217  constexpr size_type size() const noexcept { return _size; }
218  constexpr size_type length() const noexcept { return _size; }
219 
220  constexpr const_reference operator[](size_type pos) const {
221  return _ptr[pos];
222  }
223 
224  JASL_CONSTEXPR_CXX14 const_reference at(size_type pos) const {
225  if (pos >= size())
226  JASL_THROW(std::out_of_range("string_view::substr"));
227  return _ptr[pos];
228  }
229 
230  constexpr const_reference front() const noexcept {
231  JASL_ASSERT(!empty(), "string_view::front(): string is empty");
232  return _ptr[0];
233  }
234 
235  constexpr const_reference back() const noexcept {
236  JASL_ASSERT(!empty(), "string_view::back(): string is empty");
237  return _ptr[_size - 1];
238  }
239 
240  JASL_CONSTEXPR_CXX14 void swap(basic_string_view& other) noexcept {
241  const value_type* p = _ptr;
242  _ptr = other._ptr;
243  other._ptr = p;
244 
245  size_type s = _size;
246  _size = other._size;
247  other._size = s;
248  }
249 
250  size_type copy(CharT* s, size_type n, size_type pos = 0) const {
251  if (pos > size())
252  JASL_THROW(std::out_of_range("string_view::copy"));
253  size_type rlen = std::min(n, size() - pos);
254  Traits::copy(s, data() + pos, rlen);
255  return rlen;
256  }
257 
258  JASL_CONSTEXPR_CXX14 basic_string_view substr(size_type pos,
259  size_type count = npos) const {
260  if (pos > size())
261  JASL_THROW(std::out_of_range("basic_string_view::substr"));
262  size_type rlen = std::min(count, size() - pos);
263  return basic_string_view(data() + pos, rlen);
264  }
265 
266  JASL_CONSTEXPR_CXX14 void remove_prefix(size_type n) noexcept {
267  JASL_ASSERT(n <= size(), "remove_prefix() can't remove more than size()");
268  _ptr += n;
269  _size -= n;
270  }
271 
272  JASL_CONSTEXPR_CXX14 void remove_suffix(size_type n) noexcept {
273  JASL_ASSERT(n <= size(), "remove_suffix() can't remove more than size()");
274  _size -= n;
275  }
276 
277  JASL_CONSTEXPR_CXX14 int compare(const basic_string_view& right) const
278  noexcept {
279  size_type rlen = std::min(size(), right.size());
280  int retval = Traits::compare(data(), right.data(), rlen);
281  if (retval == 0) // first rlen chars matched
282  retval = size() == right.size() ? 0 : (size() < right.size() ? -1 : 1);
283  return retval;
284  }
285 
286  JASL_CONSTEXPR_CXX14
287  size_type find(const basic_string_view& s) const noexcept {
288  JASL_ASSERT(s.size() == 0 || s.data() != nullptr,
289  "string_view::find(): received nullptr");
290  auto itWhere = cbegin();
291  auto itWhat = s.cbegin();
292  while (itWhere != cend() && itWhat != s.cend()) {
293  if (*itWhere != *itWhat) {
294  ++itWhere;
295  } else {
296  auto match = itWhere++;
297  ++itWhat;
298  while (itWhere != cend() && itWhat != s.cend() && *itWhere == *itWhat) {
299  ++itWhere;
300  ++itWhat;
301  }
302  if (itWhat == s.cend()) {
303  return static_cast<size_type>(match - cbegin());
304  }
305  itWhat = s.cbegin();
306  }
307  }
308  return npos;
309  }
310 };
311 
312 // http://en.cppreference.com/w/cpp/algorithm/lexicographical_compare
313 
314 template <typename CharT, typename Traits>
315 JASL_CONSTEXPR_CXX14 bool operator==(
316  const basic_string_view<CharT, Traits>& left,
317  const basic_string_view<CharT, Traits>& right) {
318  if (left.size() != right.size()) {
319  return false;
320  }
321  return left.compare(right) == 0;
322 }
323 
324 template <typename CharT, typename Traits>
325 JASL_CONSTEXPR_CXX14 bool operator!=(
326  const basic_string_view<CharT, Traits>& left,
327  const basic_string_view<CharT, Traits>& right) {
328  return left.compare(right) != 0;
329 }
330 
331 template <typename CharT, typename Traits>
332 JASL_CONSTEXPR_CXX14 bool operator<(
333  const basic_string_view<CharT, Traits>& left,
334  const basic_string_view<CharT, Traits>& right) {
335  return left.compare(right) < 0;
336 }
337 
338 template <typename CharT, typename Traits>
339 JASL_CONSTEXPR_CXX14 bool operator<=(
340  const basic_string_view<CharT, Traits>& left,
341  const basic_string_view<CharT, Traits>& right) {
342  return left.compare(right) <= 0;
343 }
344 
345 template <typename CharT, typename Traits>
346 JASL_CONSTEXPR_CXX14 bool operator>(
347  const basic_string_view<CharT, Traits>& left,
348  const basic_string_view<CharT, Traits>& right) {
349  return left.compare(right) > 0;
350 }
351 
352 template <typename CharT, typename Traits>
353 JASL_CONSTEXPR_CXX14 bool operator>=(
354  const basic_string_view<CharT, Traits>& left,
355  const basic_string_view<CharT, Traits>& right) {
356  return left.compare(right) >= 0;
357 }
358 
359 template <class CharT, class Traits>
360 std::basic_ostream<CharT, Traits>& operator<<(
361  std::basic_ostream<CharT, Traits>& os,
362  basic_string_view<CharT, Traits> v) {
363  os.write(v.data(), static_cast<std::make_signed<size_t>::type>(v.size()));
364  return os;
365 }
366 
367 template <typename CharT, typename Traits>
368 void swap(
369  basic_string_view<CharT, Traits>& lhs,
370  basic_string_view<CharT, Traits>& rhs) noexcept(noexcept(lhs.swap(rhs))) {
371  lhs.swap(rhs);
372 }
373 
374 } // namespace nonstd
375 } // namespace jasl
376 
377 #if defined(JASL_FORCE_USE_MURMURHASH_HASH) && \
378  defined(JASL_DISABLE_JASL_STRING_VIEW_HASH)
379 # error "Illegal configration!"
380 #endif
381 
382 /*
383  * http://en.cppreference.com/w/cpp/utility/hash
384  */
385 #if !defined(JASL_DISABLE_JASL_STRING_VIEW_HASH)
386 # if defined(JASL_cpp_lib_string_view) && \
387  !defined(JASL_FORCE_USE_MURMURHASH_HASH)
388 # include <string_view>
389 namespace std {
390 template <typename CharT, typename Traits>
391 struct hash<jasl::nonstd::basic_string_view<CharT, Traits>> {
392  size_t operator()(
393  const jasl::nonstd::basic_string_view<CharT, Traits>& x) const noexcept {
394  return std::hash<std::basic_string_view<CharT, Traits>>{}(
395  std::basic_string_view<CharT, Traits>(x.data(), x.size()));
396  }
397 };
398 } // namespace std
399 # else
400 # include "jasl/jasl_internal/jasl_murmurhash3.hpp"
401 namespace std {
402 template <typename CharT, typename Traits>
403 struct hash<jasl::nonstd::basic_string_view<CharT, Traits>> {
404  size_t operator()(
405  const jasl::nonstd::basic_string_view<CharT, Traits>& x) const noexcept {
406  static_assert(sizeof(size_t) <= 16, "Unexpected platform!");
407  size_t res[16 / sizeof(size_t)];
408  auto len = static_cast<int>(
409  std::min(x.size() * sizeof(CharT),
410  static_cast<size_t>(std::numeric_limits<int>::max())));
411  if (sizeof(size_t) >= 8) {
412  jasl::murmurhash3::MurmurHash3_x64_128(x.data(), len, 33, &res);
413  } else {
414  jasl::murmurhash3::MurmurHash3_x86_128(x.data(), len, 33, &res);
415  }
416  return res[0];
417  }
418 };
419 } // namespace std
420 # endif // JASL_cpp_lib_string_view
421 #endif // JASL_DISABLE_JASL_STRING_VIEW_HASH
Definition: jasl_static_string.hpp:18
Definition: jasl_string_view.hpp:401
nonstd::basic_string_view< CharT, Traits > basic_string_view
Definition: jasl_string_view.hpp:76
Definition: jasl_string_view.hpp:24