• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_STRINGS_CSTRING_VIEW_H_
6 #define BASE_STRINGS_CSTRING_VIEW_H_
7 
8 #include <algorithm>
9 #include <concepts>
10 #include <cstddef>
11 #include <ostream>
12 #include <string>
13 #include <string_view>
14 
15 #include "base/check.h"
16 #include "base/compiler_specific.h"
17 #include "base/containers/checked_iterators.h"
18 #include "base/memory/raw_ptr_exclusion.h"
19 #include "base/numerics/safe_conversions.h"
20 #include "build/build_config.h"
21 
22 namespace base {
23 
24 // A CString is a NUL-terminated character array, which is the C programming
25 // language representation of a string. This class (and its aliases below)
26 // provides a non-owning and bounds-safe view of a CString, and can replace all
27 // use of native pointers (such as `const char*`) for this purpose in C++ code.
28 //
29 // The basic_cstring_view class is followed by aliases for the various char
30 // types:
31 // * cstring_view provides a view of a `const char*`.
32 // * u16cstring_view provides a view of a `const char16_t*`.
33 // * u32cstring_view provides a view of a `const char32_t*`.
34 // * wcstring_view provides a view of a `const wchar_t*`.
35 template <class Char>
36 class basic_cstring_view final {
37   static_assert(!std::is_const_v<Char>);
38   static_assert(!std::is_reference_v<Char>);
39 
40  public:
41   using value_type = Char;
42   using pointer = Char*;
43   using const_pointer = const Char*;
44   using reference = Char&;
45   using const_reference = const Char&;
46   using iterator = CheckedContiguousIterator<const Char>;
47   using const_iterator = CheckedContiguousIterator<const Char>;
48   using reverse_iterator = std::reverse_iterator<iterator>;
49   using const_reverse_iterator = std::reverse_iterator<iterator>;
50   using size_type = size_t;
51   using difference_type = ptrdiff_t;
52 
53   // The `npos` constant represents a non-existent position in the cstring view.
54   constexpr static auto npos = static_cast<size_t>(-1);
55 
56   // Constructs an empty cstring view, which points to an empty string with a
57   // terminating NUL.
basic_cstring_view()58   constexpr basic_cstring_view() noexcept : ptr_(kEmpty), len_(0u) {}
59 
60   // cstring views are trivially copyable, moveable, and destructible.
61 
62   // Constructs a cstring view that points at the contents of a string literal.
63   //
64   // Example:
65   // ```
66   // const char kLiteral[] = "hello world";
67   // auto s = base::cstring_view(kLiteral);
68   // CHECK(s == "hello world");
69   // auto s2 = base::cstring_view("this works too");
70   // CHECK(s == "this works too");
71   // ```
72   //
73   // The string will end at the first NUL character in the given array.
74   //
75   // Example:
76   // ```
77   // auto s = base::cstring_view("hello\0world");
78   // CHECK(s == "hello");
79   // ```
80   template <int&..., size_t M>
81   // NOLINTNEXTLINE(google-explicit-constructor)
basic_cstring_view(const Char (& lit LIFETIME_BOUND)[M])82   constexpr basic_cstring_view(const Char (&lit LIFETIME_BOUND)[M]) noexcept
83       ENABLE_IF_ATTR(lit[M - 1u] == Char{0}, "requires string literal as input")
84       : ptr_(lit), len_(std::char_traits<Char>::length(lit)) {
85     // For non-clang compilers. On clang, the function is not even callable
86     // without this being known to pass at compile time.
87     //
88     // SAFETY: lit is an array of size M, so M-1 is in bounds.
89     DCHECK_EQ(UNSAFE_BUFFERS(lit[M - 1u]), Char{0});
90   }
91 
92   // Constructs a cstring view from a std::string (or other std::basic_string
93   // type). The string parameter must outlive the cstring view, including that
94   // it must not be moved-from or destroyed.
95   //
96   // This conversion is implicit, which matches the conversion from std::string
97   // to std::string_view (through string's `operator string_view()`).
98   //
99   // # Interaction with SSO
100   // std::string stores its contents inline when they fit (which is an
101   // implementation defined length), instead of in a heap-allocated buffer. This
102   // is referred to as the Small String Optimization. This means that moving or
103   // destring a std::string will invalidate a cstring view and leave it with
104   // dangling pointers. This differs from the behaviour of std::vector and span,
105   // since pointers into a std::vector remain valid after moving the std::vector
106   // and destroying the original.
107   //
108   // # Preventing implicit temporaries
109   // Because std::string can be implicitly constructed, the string constructor
110   // may unintentionally be called with a temporary `std::string` when called
111   // with values that convert to `std::string`. We prevent this templating this
112   // constructor and requiring the incoming type to actually be a `std::string`
113   // (or other `std::basic_string`). This also improves compiler errors,
114   // compared to deleting a string&& overload, when passed an array that does
115   // not match the `ENABLE_IF_ATTR` constructor condition by not sending it to a
116   // deleted overload receiving `std::string`.
117   template <std::same_as<std::basic_string<Char>> String>
118   // NOLINTNEXTLINE(google-explicit-constructor)
basic_cstring_view(const String & s LIFETIME_BOUND)119   constexpr basic_cstring_view(const String& s LIFETIME_BOUND) noexcept
120       : ptr_(s.c_str()), len_(s.size()) {}
121 
122   // Unsafe construction from a NUL-terminated cstring, primarily for use with C
123   // APIs. Prefer to construct cstring view from a string literal, std::string,
124   // or another cstring view.
125   //
126   // # Safety
127   // The `ptr` must point to a NUL-terminated string or Undefined Behaviour will
128   // result.
129   //
130   // # Implementation note
131   // We use a `String&&` template to ensure the input is a pointer and not an
132   // array that decayed to a pointer. This ensures the ctor will not act as a
133   // fallback for the string literal ctor when the enable_if condition fails.
134   template <class String>
135     requires(std::same_as<std::remove_cvref_t<String>, Char*> ||
136              std::same_as<std::remove_cvref_t<String>, const Char*>)
basic_cstring_view(String && ptr LIFETIME_BOUND)137   UNSAFE_BUFFER_USAGE explicit constexpr basic_cstring_view(
138       String&& ptr LIFETIME_BOUND) noexcept
139       : ptr_(ptr), len_(std::char_traits<Char>::length(ptr)) {}
140 
141   // Unsafe construction from a NUL-terminated pointer and length. This allows
142   // the string to contain embedded NULs. Prefer to construct cstring view from
143   // a string literal, std::string, or another cstring view.
144   //
145   // # Safety
146   // The `ptr` and `len` pair indicate a valid NUL-terminated string:
147   // * The `ptr` must not be null, and must point to a NUL-terminated string.
148   // * The `len` must be valid such that `ptr + len` gives a pointer to the
149   //   terminating NUL and is in the same allocation as `ptr`.
basic_cstring_view(const Char * ptr LIFETIME_BOUND,size_t len)150   UNSAFE_BUFFER_USAGE explicit constexpr basic_cstring_view(const Char* ptr
151                                                                 LIFETIME_BOUND,
152                                                             size_t len)
153       : ptr_(ptr), len_(len) {
154     // This method is marked UNSAFE_BUFFER_USAGE so we are trusting the caller
155     // to do things right, and expecting strong scrutiny at the call site, but
156     // we perform a debug check to help catch mistakes regardless.
157     //
158     // SAFETY: `ptr` points to `len` many chars and then a NUL, according to the
159     // caller of this method. So then `len` index will be in bounds and return
160     // the NUL.
161     DCHECK_EQ(UNSAFE_BUFFERS(ptr[len]), Char{0});
162   }
163 
164   // Returns a pointer to the NUL-terminated string, for passing to C-style APIs
165   // that require `const char*` (or whatever the `Char` type is).
166   //
167   // This is never null.
c_str()168   PURE_FUNCTION constexpr const Char* c_str() const noexcept { return ptr_; }
169 
170   // Returns a pointer to underlying buffer. To get a string pointer, use
171   // `c_str()`.
172   //
173   // Pair with `size()` to construct a bounded non-NUL-terminated view, such as
174   // by `base::span`. This is never null.
data()175   PURE_FUNCTION constexpr const Char* data() const noexcept { return ptr_; }
176 
177   // Returns the number of characters in the string, not including the
178   // terminating NUL.
size()179   PURE_FUNCTION constexpr size_t size() const noexcept { return len_; }
180   // An alias for `size()`, returning the number of characters in the string.
length()181   PURE_FUNCTION constexpr size_t length() const noexcept { return len_; }
182 
183   // Returns whether the cstring view is for an empty string. When empty, it is
184   // pointing to a cstring that contains only a NUL character.
empty()185   PURE_FUNCTION constexpr bool empty() const noexcept { return len_ == 0u; }
186 
187   // Returns the maximum number of characters that can be represented inside the
188   // cstring view for character type `Char`.
189   //
190   // This is the number of `Char` objects that can fit inside an addressable
191   // byte array. Since the number of bytes allowed is fixed, the number returned
192   // is smaller when the `Char` is a larger type.
max_size()193   PURE_FUNCTION constexpr size_t max_size() const noexcept {
194     return static_cast<size_t>(-1) / sizeof(Char);
195   }
196 
197   // Returns the number of bytes in the string, not including the terminating
198   // NUL. To include the NUL, add `sizeof(Char)` where `Char` is the character
199   // type of the cstring view (accessible as the `value_type` alias).
size_bytes()200   PURE_FUNCTION constexpr size_t size_bytes() const noexcept {
201     return len_ * sizeof(Char);
202   }
203 
204   // Produces an iterator over the cstring view, excluding the terminating NUL.
begin()205   PURE_FUNCTION constexpr iterator begin() const noexcept {
206     // SAFETY: `ptr_ + len_` for a cstring view always gives a pointer in
207     // the same allocation as `ptr_` based on the precondition of
208     // the type.
209     return UNSAFE_BUFFERS(iterator(ptr_, ptr_ + len_));
210   }
211   // Produces an iterator over the cstring view, excluding the terminating NUL.
end()212   PURE_FUNCTION constexpr iterator end() const noexcept {
213     // SAFETY: `ptr_ + len_` for a cstring view always gives a pointer in
214     // the same allocation as `ptr_` based on the precondition of
215     // the type.
216     return UNSAFE_BUFFERS(iterator(ptr_, ptr_ + len_, ptr_ + len_));
217   }
218   // Produces an iterator over the cstring view, excluding the terminating NUL.
cbegin()219   PURE_FUNCTION constexpr const_iterator cbegin() const noexcept {
220     return begin();
221   }
222   // Produces an iterator over the cstring view, excluding the terminating NUL.
cend()223   PURE_FUNCTION constexpr const_iterator cend() const noexcept { return end(); }
224 
225   // Produces a reverse iterator over the cstring view, excluding the
226   // terminating NUL.
rbegin()227   PURE_FUNCTION constexpr reverse_iterator rbegin() const noexcept {
228     return std::reverse_iterator(end());
229   }
230   // Produces a reverse iterator over the cstring view, excluding the
231   // terminating NUL.
rend()232   PURE_FUNCTION constexpr reverse_iterator rend() const noexcept {
233     return std::reverse_iterator(begin());
234   }
235   // Produces a reverse iterator over the cstring view, excluding the
236   // terminating NUL.
rcbegin()237   PURE_FUNCTION constexpr const_reverse_iterator rcbegin() const noexcept {
238     return std::reverse_iterator(cend());
239   }
240   // Produces a reverse iterator over the cstring view, excluding the
241   // terminating NUL.
rcend()242   PURE_FUNCTION constexpr const_reverse_iterator rcend() const noexcept {
243     return std::reverse_iterator(cbegin());
244   }
245 
246   // Returns the character at offset `idx`.
247   //
248   // This can be used to access any character in the ctring, as well as the NUL
249   // terminator.
250   //
251   // # Checks
252   // The function CHECKs that the `idx` is inside the cstring (including at its
253   // NUL terminator) and will terminate otherwise.
254   PURE_FUNCTION constexpr const Char& operator[](size_t idx) const noexcept {
255     CHECK_LE(idx, len_);
256     // SAFETY: `ptr_` points `len_` many elements plus a NUL terminator, and
257     // `idx <= len_`, so `idx` is in range for `ptr_`.
258     return UNSAFE_BUFFERS(ptr_[idx]);
259   }
260 
261   // A named function that performs the same as `operator[]`.
at(size_t idx)262   PURE_FUNCTION constexpr const Char& at(size_t idx) const noexcept {
263     return (*this)[idx];
264   }
265 
266   // Returns the first character in the cstring view.
267   //
268   // # Checks
269   // The function CHECKs that the string is non-empty, and will terminate
270   // otherwise.
front()271   PURE_FUNCTION constexpr const Char& front() const noexcept {
272     CHECK(len_);
273     // Since `len_ > 0`, 0 is a valid offset into the string contents.
274     return UNSAFE_BUFFERS(ptr_[0u]);
275   }
276 
277   // Returns the last (non-NUL) character in the cstring view.
278   //
279   // # Checks
280   // The function CHECKs that the string is non-empty, and will terminate
281   // otherwise.
back()282   PURE_FUNCTION constexpr const Char& back() const noexcept {
283     CHECK(len_);
284     // Since `len_ > 0`, `len - 1` will not underflow. There are `len_` many
285     // chars in the string before a NUL, so `len_ - 1` is in range of the string
286     // contents.
287     return UNSAFE_BUFFERS(ptr_[len_ - 1u]);
288   }
289 
290   // Modifies the cstring view in place, moving the front ahead by `n`
291   // characters.
292   //
293   // # Checks
294   // The function CHECKs that `n <= size()`, and will terminate otherwise.
remove_prefix(size_t n)295   constexpr void remove_prefix(size_t n) noexcept {
296     CHECK_LE(n, len_);
297     // SAFETY: Since `n <= len_`, the pointer at offset `n` is inside the string
298     // (or at the terminating NUL) and the `len_ - n` value will not underflow.
299     // Thus the resulting pointer is still a NUL- terminated string of length
300     // `len_ - n`.
301     ptr_ = UNSAFE_BUFFERS(ptr_ + n);
302     len_ = len_ - n;
303   }
304 
305   // No `remove_suffix()` method exists as it would remove the terminating NUL
306   // character. Convert to a `std::string_view` (either by construction or with
307   // a `substr(0u)` call) to construct arbitrary substrings that are not
308   // NUL-terminated.
309   void remove_suffix(size_t n) = delete;
310 
311   // Modifies the cstring view in place, swapping its contents with another view
312   // of the same type.
swap(basic_cstring_view & other)313   constexpr void swap(basic_cstring_view& other) noexcept {
314     std::swap(ptr_, other.ptr_);
315     std::swap(len_, other.len_);
316   }
317 
318   // Returns a string view of the subrange starting as `pos` and including
319   // `count` characters. If `count` is not specified, or exceeds the length of
320   // the string after `pos`, the subrange returned will include all characters
321   // up to the terminating NUL.
322   //
323   // # Checks
324   // The function CHECKs that `pos` is in range for the string (or at the
325   // terminating NULL), and will terminate otherwise.
326   PURE_FUNCTION constexpr std::basic_string_view<Char> substr(
327       size_t pos,
328       size_t count = npos) const noexcept {
329     // Ensure `ptr_ + pos` is valid. and `len_ - pos` does not underflow.
330     CHECK_LE(pos, len_);
331     // SAFETY: We require that:
332     // * `ptr_ + pos` is a pointer in the string.
333     // * `pos + count <= len_` so that resulting substring's end is in range.
334     //
335     // The first follows directly from the CHECK above that `pos <= len_`. The
336     // second follows from clamping `count` to at most `len_ - pos`.
337     return UNSAFE_BUFFERS(
338         std::basic_string_view<Char>(ptr_ + pos, std::min(count, len_ - pos)));
339   }
340 
341   // Returns whether the cstring view starts with the given `prefix`. Will
342   // always return false if `prefix` is larger than the current cstring view.
starts_with(std::basic_string_view<Char> prefix)343   constexpr bool starts_with(
344       std::basic_string_view<Char> prefix) const noexcept {
345     return std::basic_string_view<Char>(*this).starts_with(prefix);
346   }
347 
348   // Returns whether the cstring view starts with the given `character`.
starts_with(Char character)349   constexpr bool starts_with(Char character) const noexcept {
350     return std::basic_string_view<Char>(*this).starts_with(character);
351   }
352 
353   // Returns whether the cstring view ends with the given `suffix`. Will
354   // always return false if `suffix` is larger than the current cstring view.
ends_with(std::basic_string_view<Char> suffix)355   constexpr bool ends_with(std::basic_string_view<Char> suffix) const noexcept {
356     return std::basic_string_view<Char>(*this).ends_with(suffix);
357   }
358 
359   // Returns whether the cstring view starts with the given `character`.
ends_with(Char character)360   constexpr bool ends_with(Char character) const noexcept {
361     return std::basic_string_view<Char>(*this).ends_with(character);
362   }
363 
364   // Returns the first position in the cstring view at which `search` is found,
365   // starting from the offset `pos`. If `pos` is not specified, the entire
366   // cstring view is searched. Returns `npos` if `search` is not found or if
367   // `pos` is out of range.
368   constexpr size_t find(std::basic_string_view<Char> search,
369                         size_t pos = 0u) const noexcept {
370     return std::basic_string_view<Char>(*this).find(search, pos);
371   }
372   constexpr size_t find(Char search, size_t pos = 0u) const noexcept {
373     return std::basic_string_view<Char>(*this).find(search, pos);
374   }
375 
376   // Returns the last position in the cstring view at which `search` is found,
377   // starting from the offset `pos`. If `pos` is not specified or is out of
378   // range, the entire cstring view is searched. Returns `npos` if `search` is
379   // not found.
380   constexpr size_t rfind(std::basic_string_view<Char> search,
381                          size_t pos = npos) const noexcept {
382     return std::basic_string_view<Char>(*this).rfind(search, pos);
383   }
384   constexpr size_t rfind(Char search, size_t pos = npos) const noexcept {
385     return std::basic_string_view<Char>(*this).rfind(search, pos);
386   }
387 
388   // Returns the first position in the cstring view at any character in the
389   // `search` is found, starting from the offset `pos`. If `pos` is not
390   // specified, the entire cstring view is searched. Returns `npos` if `search`
391   // is not found or if `pos` is out of range.
392   constexpr size_t find_first_of(std::basic_string_view<Char> search,
393                                  size_t pos = 0u) const noexcept {
394     return std::basic_string_view<Char>(*this).find_first_of(search, pos);
395   }
396   constexpr size_t find_first_of(Char search, size_t pos = 0u) const noexcept {
397     return std::basic_string_view<Char>(*this).find_first_of(search, pos);
398   }
399 
400   // Returns the last position in the cstring view at any character in the
401   // `search` is found, starting from the offset `pos`. If `pos` is not
402   // specified or is out of range, the entire cstring view is searched. Returns
403   // `npos` if `search` is not found.
404   constexpr size_t find_last_of(std::basic_string_view<Char> search,
405                                 size_t pos = npos) const noexcept {
406     return std::basic_string_view<Char>(*this).find_last_of(search, pos);
407   }
408   constexpr size_t find_last_of(Char search, size_t pos = npos) const noexcept {
409     return std::basic_string_view<Char>(*this).find_last_of(search, pos);
410   }
411 
412   // Returns the first position in the cstring view that is not equal to any
413   // character in the `search`, starting from the offset `pos`. If `pos` is not
414   // specified, the entire cstring view is searched. Returns `npos` if every
415   // character is part of `search` or if `pos` is out of range.
416   constexpr size_t find_first_not_of(std::basic_string_view<Char> search,
417                                      size_t pos = 0u) const noexcept {
418     return std::basic_string_view<Char>(*this).find_first_not_of(search, pos);
419   }
420   constexpr size_t find_first_not_of(Char search,
421                                      size_t pos = 0u) const noexcept {
422     return std::basic_string_view<Char>(*this).find_first_not_of(search, pos);
423   }
424 
425   // Returns the last position in the cstring view that is not equal to any
426   // character in the `search`, starting from the offset `pos`. If `pos` is not
427   // specified or is out of range, the entire cstring view is searched.  Returns
428   // `npos` if every character is part of `search`.
429   constexpr size_t find_last_not_of(std::basic_string_view<Char> search,
430                                     size_t pos = npos) const noexcept {
431     return std::basic_string_view<Char>(*this).find_last_not_of(search, pos);
432   }
433   constexpr size_t find_last_not_of(Char search,
434                                     size_t pos = npos) const noexcept {
435     return std::basic_string_view<Char>(*this).find_last_not_of(search, pos);
436   }
437 
438   // Compare two cstring views for equality, comparing the string contents.
439   friend constexpr bool operator==(basic_cstring_view l, basic_cstring_view r) {
440     return std::ranges::equal(l, r);
441   }
442 
443   // Return an ordering between two cstring views, comparing the string
444   // contents.
445   //
446   // cstring views are weakly ordered, since string views pointing into
447   // different strings can compare as equal.
448   friend constexpr std::weak_ordering operator<=>(basic_cstring_view l,
449                                                   basic_cstring_view r) {
450     return std::lexicographical_compare_three_way(l.begin(), l.end(), r.begin(),
451                                                   r.end());
452   }
453 
454   // Implicitly converts from cstring_view to a non-NUL-terminated
455   // std::string_view. The std::string_view type implicitly constructs from
456   // `const char*` and cstring view is meant to replace the latter, so this acts
457   // like an implicit constructor on `std::string_view` for cstring views.
458   //
459   // This operator also avoids a requirement on having overloads for both
460   // std::string_view and cstring_view. Such overloads are ambiguous because
461   // both can construct from a character array.
462   //
463   // NOLINTNEXTLINE(google-explicit-constructor)
464   constexpr operator std::basic_string_view<Char>() const noexcept {
465     // SAFETY: The cstring view provides that `ptr_ + len_` to be valid.
466     return UNSAFE_BUFFERS(std::basic_string_view<Char>(ptr_, len_));
467   }
468 
469   // Converts from cstring_view to std::string. This allocates a new string
470   // backing and copies into it.
471   //
472   // The std::string type implicitly constructs from `const char*` however it
473   // does not implicitly construct from std::string_view. This type sits between
474   // these two, and opts towards making heap allocations explicit by requiring
475   // an explicit conversion.
476   constexpr explicit operator std::basic_string<Char>() const noexcept {
477     // SAFETY: The cstring view provides that `ptr_ + len_` to be valid.
478     return UNSAFE_BUFFERS(std::basic_string<Char>(ptr_, len_));
479   }
480 
481   // Concatenate a std::string with a cstring_view to produce another
482   // std::string.
483   //
484   // These act like overloads on `std::string` that work for concatenating
485   // `std::string` and `const char*`.
486   //
487   // The rvalue overloads allow `std::string` to reuse existing capacity, by
488   // calling through to the rvalue overloads on `std::string`.
489   template <class Traits, class Alloc>
490   friend constexpr std::basic_string<Char, Traits, Alloc> operator+(
491       basic_cstring_view lhs,
492       const std::basic_string<Char, Traits, Alloc>& rhs) {
493     return lhs.c_str() + rhs;
494   }
495   template <class Traits, class Alloc>
496   friend constexpr std::basic_string<Char, Traits, Alloc> operator+(
497       basic_cstring_view lhs,
498       std::basic_string<Char, Traits, Alloc>&& rhs) {
499     return lhs.c_str() + std::move(rhs);
500   }
501   template <class Traits, class Alloc>
502   friend constexpr std::basic_string<Char, Traits, Alloc> operator+(
503       const std::basic_string<Char, Traits, Alloc>& lhs,
504       basic_cstring_view rhs) {
505     return lhs + rhs.c_str();
506   }
507   template <class Traits, class Alloc>
508   friend constexpr std::basic_string<Char, Traits, Alloc> operator+(
509       std::basic_string<Char, Traits, Alloc>&& lhs,
510       basic_cstring_view rhs) {
511     return std::move(lhs) + rhs.c_str();
512   }
513 
514  private:
515   // An empty string literal for the `Char` type.
516   static constexpr Char kEmpty[] = {Char{0}};
517 
518   // An always-valid pointer (never null) to a NUL-terminated string.
519   //
520   // RAW_PTR_EXCLUSION: cstring_view is typically used on the stack as a local
521   // variable/function parameter, so no raw_ptr is used here.
522   RAW_PTR_EXCLUSION const Char* ptr_;
523   // The number of characters between `ptr_` and the NUL terminator.
524   //
525   // SAFETY: `ptr_ + len_` is always valid since `len_` must not exceed the
526   // number of characters in the allocation, or it would no longer indicate the
527   // position of the NUL terminator in the string allocation.
528   size_t len_;
529 };
530 
531 // cstring_view provides a view of a NUL-terminated string. It is a replacement
532 // for all use of `const char*`, in order to provide bounds checks and prevent
533 // unsafe pointer usage (otherwise prevented by `-Wunsafe-buffer-usage`).
534 //
535 // See basic_cstring_view for more.
536 using cstring_view = basic_cstring_view<char>;
537 
538 // u16cstring_view provides a view of a NUL-terminated string. It is a
539 // replacement for all use of `const char16_t*`, in order to provide bounds
540 // checks and prevent unsafe pointer usage (otherwise prevented by
541 // `-Wunsafe-buffer-usage`).
542 //
543 // See basic_cstring_view for more.
544 using u16cstring_view = basic_cstring_view<char16_t>;
545 
546 // u32cstring_view provides a view of a NUL-terminated string. It is a
547 // replacement for all use of `const char32_t*`, in order to provide bounds
548 // checks and prevent unsafe pointer usage (otherwise prevented by
549 // `-Wunsafe-buffer-usage`).
550 //
551 // See basic_cstring_view for more.
552 using u32cstring_view = basic_cstring_view<char32_t>;
553 
554 #if BUILDFLAG(IS_WIN)
555 // wcstring_view provides a view of a NUL-terminated string. It is a
556 // replacement for all use of `const wchar_t*`, in order to provide bounds
557 // checks and prevent unsafe pointer usage (otherwise prevented by
558 // `-Wunsafe-buffer-usage`).
559 //
560 // See basic_cstring_view for more.
561 using wcstring_view = basic_cstring_view<wchar_t>;
562 #endif
563 
564 // Writes the contents of the cstring view to the stream.
565 template <class Char, class Traits>
566 std::basic_ostream<Char, Traits>& operator<<(
567     std::basic_ostream<Char, Traits>& os,
568     basic_cstring_view<Char> view) {
569   return os << std::basic_string_view<Char>(view);
570 }
571 
572 // Explicitly define PrintTo to avoid gtest printing these as containers
573 // rather than strings.
PrintTo(cstring_view view,std::ostream * os)574 inline void PrintTo(cstring_view view, std::ostream* os) {
575   *os << view;
576 }
577 
578 }  // namespace base
579 
580 template <class Char>
581 struct std::hash<base::basic_cstring_view<Char>> {
582   size_t operator()(const base::basic_cstring_view<Char>& t) const noexcept {
583     return std::hash<std::basic_string_view<Char>>()(t);
584   }
585 };
586 
587 template <class Char>
588 inline constexpr bool
589     std::ranges::enable_borrowed_range<base::basic_cstring_view<Char>> = true;
590 
591 template <class Char>
592 inline constexpr bool std::ranges::enable_view<base::basic_cstring_view<Char>> =
593     true;
594 
595 #endif  // BASE_STRINGS_CSTRING_VIEW_H_
596