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