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