libstdc++
string_view
Go to the documentation of this file.
1 // Components for manipulating non-owning sequences of characters -*- C++ -*-
2 
3 // Copyright (C) 2013-2019 Free Software Foundation, Inc.
4 //
5 // This file is part of the GNU ISO C++ Library. This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option)
9 // any later version.
10 
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
19 
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23 // <http://www.gnu.org/licenses/>.
24 
25 /** @file experimental/string_view
26  * This is a TS C++ Library header.
27  */
28 
29 //
30 // N3762 basic_string_view library
31 //
32 
33 #ifndef _GLIBCXX_EXPERIMENTAL_STRING_VIEW
34 #define _GLIBCXX_EXPERIMENTAL_STRING_VIEW 1
35 
36 #pragma GCC system_header
37 
38 #if __cplusplus >= 201402L
39 
40 #include <string>
41 #include <limits>
42 #include <experimental/bits/lfts_config.h>
43 
44 namespace std _GLIBCXX_VISIBILITY(default)
45 {
46 _GLIBCXX_BEGIN_NAMESPACE_VERSION
47 
48 namespace experimental
49 {
50 inline namespace fundamentals_v1
51 {
52 #define __cpp_lib_experimental_string_view 201411
53 
54  /**
55  * @class basic_string_view <experimental/string_view>
56  * @brief A non-owning reference to a string.
57  *
58  * @ingroup strings
59  * @ingroup sequences
60  * @ingroup experimental
61  *
62  * @tparam _CharT Type of character
63  * @tparam _Traits Traits for character type, defaults to
64  * char_traits<_CharT>.
65  *
66  * A basic_string_view looks like this:
67  *
68  * @code
69  * _CharT* _M_str
70  * size_t _M_len
71  * @endcode
72  */
73  template<typename _CharT, typename _Traits = std::char_traits<_CharT>>
74  class basic_string_view
75  {
76  public:
77 
78  // types
79  using traits_type = _Traits;
80  using value_type = _CharT;
81  using pointer = _CharT*;
82  using const_pointer = const _CharT*;
83  using reference = _CharT&;
84  using const_reference = const _CharT&;
85  using const_iterator = const _CharT*;
86  using iterator = const_iterator;
87  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
88  using reverse_iterator = const_reverse_iterator;
89  using size_type = size_t;
90  using difference_type = ptrdiff_t;
91  static constexpr size_type npos = size_type(-1);
92 
93  // [string.view.cons], construct/copy
94 
95  constexpr
96  basic_string_view() noexcept
97  : _M_len{0}, _M_str{nullptr}
98  { }
99 
100  constexpr basic_string_view(const basic_string_view&) noexcept = default;
101 
102  template<typename _Allocator>
103  basic_string_view(const basic_string<_CharT, _Traits,
104  _Allocator>& __str) noexcept
105  : _M_len{__str.length()}, _M_str{__str.data()}
106  { }
107 
108  constexpr basic_string_view(const _CharT* __str)
109  : _M_len{__str == nullptr ? 0 : traits_type::length(__str)},
110  _M_str{__str}
111  { }
112 
113  constexpr basic_string_view(const _CharT* __str, size_type __len)
114  : _M_len{__len},
115  _M_str{__str}
116  { }
117 
118  basic_string_view&
119  operator=(const basic_string_view&) noexcept = default;
120 
121  // [string.view.iterators], iterators
122 
123  constexpr const_iterator
124  begin() const noexcept
125  { return this->_M_str; }
126 
127  constexpr const_iterator
128  end() const noexcept
129  { return this->_M_str + this->_M_len; }
130 
131  constexpr const_iterator
132  cbegin() const noexcept
133  { return this->_M_str; }
134 
135  constexpr const_iterator
136  cend() const noexcept
137  { return this->_M_str + this->_M_len; }
138 
139  const_reverse_iterator
140  rbegin() const noexcept
141  { return const_reverse_iterator(this->end()); }
142 
143  const_reverse_iterator
144  rend() const noexcept
145  { return const_reverse_iterator(this->begin()); }
146 
147  const_reverse_iterator
148  crbegin() const noexcept
149  { return const_reverse_iterator(this->end()); }
150 
151  const_reverse_iterator
152  crend() const noexcept
153  { return const_reverse_iterator(this->begin()); }
154 
155  // [string.view.capacity], capacity
156 
157  constexpr size_type
158  size() const noexcept
159  { return this->_M_len; }
160 
161  constexpr size_type
162  length() const noexcept
163  { return _M_len; }
164 
165  constexpr size_type
166  max_size() const noexcept
167  {
168  return (npos - sizeof(size_type) - sizeof(void*))
169  / sizeof(value_type) / 4;
170  }
171 
172  _GLIBCXX_NODISCARD constexpr bool
173  empty() const noexcept
174  { return this->_M_len == 0; }
175 
176  // [string.view.access], element access
177 
178  constexpr const _CharT&
179  operator[](size_type __pos) const
180  {
181  // TODO: Assert to restore in a way compatible with the constexpr.
182  // __glibcxx_assert(__pos < this->_M_len);
183  return *(this->_M_str + __pos);
184  }
185 
186  constexpr const _CharT&
187  at(size_type __pos) const
188  {
189  return __pos < this->_M_len
190  ? *(this->_M_str + __pos)
191  : (__throw_out_of_range_fmt(__N("basic_string_view::at: __pos "
192  "(which is %zu) >= this->size() "
193  "(which is %zu)"),
194  __pos, this->size()),
195  *this->_M_str);
196  }
197 
198  constexpr const _CharT&
199  front() const
200  {
201  // TODO: Assert to restore in a way compatible with the constexpr.
202  // __glibcxx_assert(this->_M_len > 0);
203  return *this->_M_str;
204  }
205 
206  constexpr const _CharT&
207  back() const
208  {
209  // TODO: Assert to restore in a way compatible with the constexpr.
210  // __glibcxx_assert(this->_M_len > 0);
211  return *(this->_M_str + this->_M_len - 1);
212  }
213 
214  constexpr const _CharT*
215  data() const noexcept
216  { return this->_M_str; }
217 
218  // [string.view.modifiers], modifiers:
219 
220  constexpr void
221  remove_prefix(size_type __n)
222  {
223  __glibcxx_assert(this->_M_len >= __n);
224  this->_M_str += __n;
225  this->_M_len -= __n;
226  }
227 
228  constexpr void
229  remove_suffix(size_type __n)
230  { this->_M_len -= __n; }
231 
232  constexpr void
233  swap(basic_string_view& __sv) noexcept
234  {
235  auto __tmp = *this;
236  *this = __sv;
237  __sv = __tmp;
238  }
239 
240 
241  // [string.view.ops], string operations:
242 
243  template<typename _Allocator>
244  explicit operator basic_string<_CharT, _Traits, _Allocator>() const
245  {
246  return { this->_M_str, this->_M_len };
247  }
248 
249  template<typename _Allocator = std::allocator<_CharT>>
250  basic_string<_CharT, _Traits, _Allocator>
251  to_string(const _Allocator& __alloc = _Allocator()) const
252  {
253  return { this->_M_str, this->_M_len, __alloc };
254  }
255 
256  size_type
257  copy(_CharT* __str, size_type __n, size_type __pos = 0) const
258  {
259  __glibcxx_requires_string_len(__str, __n);
260  if (__pos > this->_M_len)
261  __throw_out_of_range_fmt(__N("basic_string_view::copy: __pos "
262  "(which is %zu) > this->size() "
263  "(which is %zu)"),
264  __pos, this->size());
265  size_type __rlen{std::min(__n, size_type{this->_M_len - __pos})};
266  for (auto __begin = this->_M_str + __pos,
267  __end = __begin + __rlen; __begin != __end;)
268  *__str++ = *__begin++;
269  return __rlen;
270  }
271 
272 
273  // [string.view.ops], string operations:
274 
275  constexpr basic_string_view
276  substr(size_type __pos = 0, size_type __n = npos) const
277  {
278  return __pos <= this->_M_len
279  ? basic_string_view{this->_M_str + __pos,
280  std::min(__n, size_type{this->_M_len - __pos})}
281  : (__throw_out_of_range_fmt(__N("basic_string_view::substr: __pos "
282  "(which is %zu) > this->size() "
283  "(which is %zu)"),
284  __pos, this->size()), basic_string_view{});
285  }
286 
287  constexpr int
288  compare(basic_string_view __str) const noexcept
289  {
290  int __ret = traits_type::compare(this->_M_str, __str._M_str,
291  std::min(this->_M_len, __str._M_len));
292  if (__ret == 0)
293  __ret = _S_compare(this->_M_len, __str._M_len);
294  return __ret;
295  }
296 
297  constexpr int
298  compare(size_type __pos1, size_type __n1, basic_string_view __str) const
299  { return this->substr(__pos1, __n1).compare(__str); }
300 
301  constexpr int
302  compare(size_type __pos1, size_type __n1,
303  basic_string_view __str, size_type __pos2, size_type __n2) const
304  { return this->substr(__pos1, __n1).compare(__str.substr(__pos2, __n2)); }
305 
306  constexpr int
307  compare(const _CharT* __str) const noexcept
308  { return this->compare(basic_string_view{__str}); }
309 
310  constexpr int
311  compare(size_type __pos1, size_type __n1, const _CharT* __str) const
312  { return this->substr(__pos1, __n1).compare(basic_string_view{__str}); }
313 
314  constexpr int
315  compare(size_type __pos1, size_type __n1,
316  const _CharT* __str, size_type __n2) const
317  {
318  return this->substr(__pos1, __n1)
319  .compare(basic_string_view(__str, __n2));
320  }
321 
322  constexpr size_type
323  find(basic_string_view __str, size_type __pos = 0) const noexcept
324  { return this->find(__str._M_str, __pos, __str._M_len); }
325 
326  constexpr size_type
327  find(_CharT __c, size_type __pos=0) const noexcept;
328 
329  constexpr size_type
330  find(const _CharT* __str, size_type __pos, size_type __n) const noexcept;
331 
332  constexpr size_type
333  find(const _CharT* __str, size_type __pos=0) const noexcept
334  { return this->find(__str, __pos, traits_type::length(__str)); }
335 
336  constexpr size_type
337  rfind(basic_string_view __str, size_type __pos = npos) const noexcept
338  { return this->rfind(__str._M_str, __pos, __str._M_len); }
339 
340  constexpr size_type
341  rfind(_CharT __c, size_type __pos = npos) const noexcept;
342 
343  constexpr size_type
344  rfind(const _CharT* __str, size_type __pos, size_type __n) const noexcept;
345 
346  constexpr size_type
347  rfind(const _CharT* __str, size_type __pos = npos) const noexcept
348  { return this->rfind(__str, __pos, traits_type::length(__str)); }
349 
350  constexpr size_type
351  find_first_of(basic_string_view __str, size_type __pos = 0) const noexcept
352  { return this->find_first_of(__str._M_str, __pos, __str._M_len); }
353 
354  constexpr size_type
355  find_first_of(_CharT __c, size_type __pos = 0) const noexcept
356  { return this->find(__c, __pos); }
357 
358  constexpr size_type
359  find_first_of(const _CharT* __str, size_type __pos, size_type __n) const;
360 
361  constexpr size_type
362  find_first_of(const _CharT* __str, size_type __pos = 0) const noexcept
363  { return this->find_first_of(__str, __pos, traits_type::length(__str)); }
364 
365  constexpr size_type
366  find_last_of(basic_string_view __str,
367  size_type __pos = npos) const noexcept
368  { return this->find_last_of(__str._M_str, __pos, __str._M_len); }
369 
370  constexpr size_type
371  find_last_of(_CharT __c, size_type __pos=npos) const noexcept
372  { return this->rfind(__c, __pos); }
373 
374  constexpr size_type
375  find_last_of(const _CharT* __str, size_type __pos, size_type __n) const;
376 
377  constexpr size_type
378  find_last_of(const _CharT* __str, size_type __pos = npos) const noexcept
379  { return this->find_last_of(__str, __pos, traits_type::length(__str)); }
380 
381  constexpr size_type
382  find_first_not_of(basic_string_view __str,
383  size_type __pos = 0) const noexcept
384  { return this->find_first_not_of(__str._M_str, __pos, __str._M_len); }
385 
386  constexpr size_type
387  find_first_not_of(_CharT __c, size_type __pos = 0) const noexcept;
388 
389  constexpr size_type
390  find_first_not_of(const _CharT* __str,
391  size_type __pos, size_type __n) const;
392 
393  constexpr size_type
394  find_first_not_of(const _CharT* __str, size_type __pos = 0) const noexcept
395  {
396  return this->find_first_not_of(__str, __pos,
397  traits_type::length(__str));
398  }
399 
400  constexpr size_type
401  find_last_not_of(basic_string_view __str,
402  size_type __pos = npos) const noexcept
403  { return this->find_last_not_of(__str._M_str, __pos, __str._M_len); }
404 
405  constexpr size_type
406  find_last_not_of(_CharT __c, size_type __pos = npos) const noexcept;
407 
408  constexpr size_type
409  find_last_not_of(const _CharT* __str,
410  size_type __pos, size_type __n) const;
411 
412  constexpr size_type
413  find_last_not_of(const _CharT* __str,
414  size_type __pos = npos) const noexcept
415  {
416  return this->find_last_not_of(__str, __pos,
417  traits_type::length(__str));
418  }
419 
420  private:
421 
422  static constexpr int
423  _S_compare(size_type __n1, size_type __n2) noexcept
424  {
425  return difference_type(__n1 - __n2) > std::numeric_limits<int>::max()
426  ? std::numeric_limits<int>::max()
427  : difference_type(__n1 - __n2) < std::numeric_limits<int>::min()
428  ? std::numeric_limits<int>::min()
429  : static_cast<int>(difference_type(__n1 - __n2));
430  }
431 
432  size_t _M_len;
433  const _CharT* _M_str;
434  };
435 
436  // [string.view.comparison], non-member basic_string_view comparison functions
437 
438  namespace __detail
439  {
440  // Identity transform to create a non-deduced context, so that only one
441  // argument participates in template argument deduction and the other
442  // argument gets implicitly converted to the deduced type. See n3766.html.
443  template<typename _Tp>
444  using __idt = common_type_t<_Tp>;
445  }
446 
447  template<typename _CharT, typename _Traits>
448  constexpr bool
449  operator==(basic_string_view<_CharT, _Traits> __x,
450  basic_string_view<_CharT, _Traits> __y) noexcept
451  { return __x.size() == __y.size() && __x.compare(__y) == 0; }
452 
453  template<typename _CharT, typename _Traits>
454  constexpr bool
455  operator==(basic_string_view<_CharT, _Traits> __x,
456  __detail::__idt<basic_string_view<_CharT, _Traits>> __y) noexcept
457  { return __x.size() == __y.size() && __x.compare(__y) == 0; }
458 
459  template<typename _CharT, typename _Traits>
460  constexpr bool
461  operator==(__detail::__idt<basic_string_view<_CharT, _Traits>> __x,
462  basic_string_view<_CharT, _Traits> __y) noexcept
463  { return __x.size() == __y.size() && __x.compare(__y) == 0; }
464 
465  template<typename _CharT, typename _Traits>
466  constexpr bool
467  operator!=(basic_string_view<_CharT, _Traits> __x,
468  basic_string_view<_CharT, _Traits> __y) noexcept
469  { return !(__x == __y); }
470 
471  template<typename _CharT, typename _Traits>
472  constexpr bool
473  operator!=(basic_string_view<_CharT, _Traits> __x,
474  __detail::__idt<basic_string_view<_CharT, _Traits>> __y) noexcept
475  { return !(__x == __y); }
476 
477  template<typename _CharT, typename _Traits>
478  constexpr bool
479  operator!=(__detail::__idt<basic_string_view<_CharT, _Traits>> __x,
480  basic_string_view<_CharT, _Traits> __y) noexcept
481  { return !(__x == __y); }
482 
483  template<typename _CharT, typename _Traits>
484  constexpr bool
485  operator< (basic_string_view<_CharT, _Traits> __x,
486  basic_string_view<_CharT, _Traits> __y) noexcept
487  { return __x.compare(__y) < 0; }
488 
489  template<typename _CharT, typename _Traits>
490  constexpr bool
491  operator< (basic_string_view<_CharT, _Traits> __x,
492  __detail::__idt<basic_string_view<_CharT, _Traits>> __y) noexcept
493  { return __x.compare(__y) < 0; }
494 
495  template<typename _CharT, typename _Traits>
496  constexpr bool
497  operator< (__detail::__idt<basic_string_view<_CharT, _Traits>> __x,
498  basic_string_view<_CharT, _Traits> __y) noexcept
499  { return __x.compare(__y) < 0; }
500 
501  template<typename _CharT, typename _Traits>
502  constexpr bool
503  operator> (basic_string_view<_CharT, _Traits> __x,
504  basic_string_view<_CharT, _Traits> __y) noexcept
505  { return __x.compare(__y) > 0; }
506 
507  template<typename _CharT, typename _Traits>
508  constexpr bool
509  operator> (basic_string_view<_CharT, _Traits> __x,
510  __detail::__idt<basic_string_view<_CharT, _Traits>> __y) noexcept
511  { return __x.compare(__y) > 0; }
512 
513  template<typename _CharT, typename _Traits>
514  constexpr bool
515  operator> (__detail::__idt<basic_string_view<_CharT, _Traits>> __x,
516  basic_string_view<_CharT, _Traits> __y) noexcept
517  { return __x.compare(__y) > 0; }
518 
519  template<typename _CharT, typename _Traits>
520  constexpr bool
521  operator<=(basic_string_view<_CharT, _Traits> __x,
522  basic_string_view<_CharT, _Traits> __y) noexcept
523  { return __x.compare(__y) <= 0; }
524 
525  template<typename _CharT, typename _Traits>
526  constexpr bool
527  operator<=(basic_string_view<_CharT, _Traits> __x,
528  __detail::__idt<basic_string_view<_CharT, _Traits>> __y) noexcept
529  { return __x.compare(__y) <= 0; }
530 
531  template<typename _CharT, typename _Traits>
532  constexpr bool
533  operator<=(__detail::__idt<basic_string_view<_CharT, _Traits>> __x,
534  basic_string_view<_CharT, _Traits> __y) noexcept
535  { return __x.compare(__y) <= 0; }
536 
537  template<typename _CharT, typename _Traits>
538  constexpr bool
539  operator>=(basic_string_view<_CharT, _Traits> __x,
540  basic_string_view<_CharT, _Traits> __y) noexcept
541  { return __x.compare(__y) >= 0; }
542 
543  template<typename _CharT, typename _Traits>
544  constexpr bool
545  operator>=(basic_string_view<_CharT, _Traits> __x,
546  __detail::__idt<basic_string_view<_CharT, _Traits>> __y) noexcept
547  { return __x.compare(__y) >= 0; }
548 
549  template<typename _CharT, typename _Traits>
550  constexpr bool
551  operator>=(__detail::__idt<basic_string_view<_CharT, _Traits>> __x,
552  basic_string_view<_CharT, _Traits> __y) noexcept
553  { return __x.compare(__y) >= 0; }
554 
555  // [string.view.io], Inserters and extractors
556  template<typename _CharT, typename _Traits>
557  inline basic_ostream<_CharT, _Traits>&
558  operator<<(basic_ostream<_CharT, _Traits>& __os,
559  basic_string_view<_CharT,_Traits> __str)
560  { return __ostream_insert(__os, __str.data(), __str.size()); }
561 
562 
563  // basic_string_view typedef names
564 
565  using string_view = basic_string_view<char>;
566 #ifdef _GLIBCXX_USE_WCHAR_T
567  using wstring_view = basic_string_view<wchar_t>;
568 #endif
569 #ifdef _GLIBCXX_USE_CHAR8_T
570  using u8string_view = basic_string_view<char8_t>;
571 #endif
572  using u16string_view = basic_string_view<char16_t>;
573  using u32string_view = basic_string_view<char32_t>;
574 } // namespace fundamentals_v1
575 } // namespace experimental
576 
577 
578  // [string.view.hash], hash support:
579  template<typename _Tp>
580  struct hash;
581 
582  template<>
583  struct hash<experimental::string_view>
584  : public __hash_base<size_t, experimental::string_view>
585  {
586  size_t
587  operator()(const experimental::string_view& __str) const noexcept
588  { return std::_Hash_impl::hash(__str.data(), __str.length()); }
589  };
590 
591  template<>
592  struct __is_fast_hash<hash<experimental::string_view>> : std::false_type
593  { };
594 
595 #ifdef _GLIBCXX_USE_WCHAR_T
596  template<>
597  struct hash<experimental::wstring_view>
598  : public __hash_base<size_t, wstring>
599  {
600  size_t
601  operator()(const experimental::wstring_view& __s) const noexcept
602  { return std::_Hash_impl::hash(__s.data(),
603  __s.length() * sizeof(wchar_t)); }
604  };
605 
606  template<>
607  struct __is_fast_hash<hash<experimental::wstring_view>> : std::false_type
608  { };
609 #endif
610 
611 #ifdef _GLIBCXX_USE_CHAR8_T
612  template<>
613  struct hash<experimental::u8string_view>
614  : public __hash_base<size_t, experimental::u8string_view>
615  {
616  size_t
617  operator()(const experimental::u8string_view& __s) const noexcept
618  { return std::_Hash_impl::hash(__s.data(), __s.length()); }
619  };
620 
621  template<>
622  struct __is_fast_hash<hash<experimental::u8string_view>> : std::false_type
623  { };
624 #endif
625 
626  template<>
627  struct hash<experimental::u16string_view>
628  : public __hash_base<size_t, experimental::u16string_view>
629  {
630  size_t
631  operator()(const experimental::u16string_view& __s) const noexcept
632  { return std::_Hash_impl::hash(__s.data(),
633  __s.length() * sizeof(char16_t)); }
634  };
635 
636  template<>
637  struct __is_fast_hash<hash<experimental::u16string_view>> : std::false_type
638  { };
639 
640  template<>
641  struct hash<experimental::u32string_view>
642  : public __hash_base<size_t, experimental::u32string_view>
643  {
644  size_t
645  operator()(const experimental::u32string_view& __s) const noexcept
646  { return std::_Hash_impl::hash(__s.data(),
647  __s.length() * sizeof(char32_t)); }
648  };
649 
650  template<>
651  struct __is_fast_hash<hash<experimental::u32string_view>> : std::false_type
652  { };
653 
654 namespace experimental
655 {
656  // I added these EMSR.
657  inline namespace literals
658  {
659  inline namespace string_view_literals
660  {
661 #pragma GCC diagnostic push
662 #pragma GCC diagnostic ignored "-Wliteral-suffix"
663  inline constexpr basic_string_view<char>
664  operator""sv(const char* __str, size_t __len) noexcept
665  { return basic_string_view<char>{__str, __len}; }
666 
667 #ifdef _GLIBCXX_USE_WCHAR_T
668  inline constexpr basic_string_view<wchar_t>
669  operator""sv(const wchar_t* __str, size_t __len) noexcept
670  { return basic_string_view<wchar_t>{__str, __len}; }
671 #endif
672 
673 #ifdef _GLIBCXX_USE_CHAR8_T
674  inline constexpr basic_string_view<char8_t>
675  operator""sv(const char8_t* __str, size_t __len) noexcept
676  { return basic_string_view<char8_t>{__str, __len}; }
677 #endif
678 
679  inline constexpr basic_string_view<char16_t>
680  operator""sv(const char16_t* __str, size_t __len) noexcept
681  { return basic_string_view<char16_t>{__str, __len}; }
682 
683  inline constexpr basic_string_view<char32_t>
684  operator""sv(const char32_t* __str, size_t __len) noexcept
685  { return basic_string_view<char32_t>{__str, __len}; }
686 #pragma GCC diagnostic pop
687  } // namespace string_literals
688  } // namespace literals
689 } // namespace experimental
690 
691 _GLIBCXX_END_NAMESPACE_VERSION
692 } // namespace std
693 
694 #include <experimental/bits/string_view.tcc>
695 
696 #endif // __cplusplus <= 201103L
697 
698 #endif // _GLIBCXX_EXPERIMENTAL_STRING_VIEW