0

span_with_nul_from_cstring_view support for cstring_view

This CL adds a variant to `span_with_nul_from_cstring_view` that
supports `basic_cstring_view<T>`. This will dispense of unsafe buffers
for usecases where a span instance for a `cstring_view` is needed to
preserve the null-terminator.

Bug: 364987728
Change-Id: Ic3dbc89c99af68ece054e0c728d2fd87a725fb32
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6063316
Reviewed-by: Peter Kasting <pkasting@chromium.org>
Commit-Queue: Claudio DeSouza <cdesouza@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1391410}
This commit is contained in:
Claudio DeSouza
2024-12-04 01:52:26 +00:00
committed by Chromium LUCI CQ
parent 5f9894b05b
commit a9844a51e5
2 changed files with 56 additions and 1 deletions
base/containers

@ -28,6 +28,7 @@
#include "base/compiler_specific.h"
#include "base/containers/checked_iterators.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/cstring_view.h"
#include "base/types/to_address.h"
// A span is a view of contiguous elements that can be accessed like an array,
@ -230,6 +231,8 @@
// (non-range) objects to spans.
// - For convenience, provides `[byte_]span_[with_nul_]from_cstring()` to
// convert `const char[]` literals to spans.
// - For convenience, provides `[byte_]span_with_nul_from_cstring_view()` to
// convert `basic_cstring_view<T>` to spans, preserving the null terminator.
// - For convenience, provides `as_[writable_]byte_span()` to convert
// spanifiable objects directly to byte spans.
@ -1451,6 +1454,17 @@ constexpr auto span_with_nul_from_cstring(
return span(str);
}
// Converts a `basic_cstring_view` instance to a `span<const CharT>`, preserving
// the trailing '\0'.
//
// (Not in `std::`; explicitly includes the trailing nul, which would be omitted
// by calling the range constructor.)
template <typename CharT>
constexpr auto span_with_nul_from_cstring_view(basic_cstring_view<CharT> str) {
// SAFETY: It is safe to read the guaranteed null-terminator in `str`.
return UNSAFE_BUFFERS(span(str.data(), str.size() + 1));
}
// Like `span_from_cstring()`, but returns a byte span.
//
// (Not in `std::`.)
@ -1478,6 +1492,15 @@ constexpr auto byte_span_with_nul_from_cstring(
return as_bytes(span(str));
}
// Like `span_with_nul_from_cstring_view()`, but returns a byte span.
//
// (Not in `std::`.)
template <typename CharT>
constexpr auto byte_span_with_nul_from_cstring_view(
basic_cstring_view<CharT> str) {
return as_bytes(span_with_nul_from_cstring_view(str));
}
// Converts an object which can already explicitly convert to some kind of span
// directly into a byte span.
//

@ -24,6 +24,7 @@
#include "base/memory/raw_span.h"
#include "base/numerics/byte_conversions.h"
#include "base/ranges/algorithm.h"
#include "base/strings/cstring_view.h"
#include "base/strings/utf_ostream_operators.h"
#include "base/test/gtest_util.h"
#include "testing/gmock/include/gmock/gmock.h"
@ -706,7 +707,16 @@ TEST(SpanTest, FromCString) {
EXPECT_EQ(s[4u], 'o');
EXPECT_EQ(s.size(), 5u);
}
// Includes the terminating null, size known at compile time.
// No terminating null, size not known at compile time. cstring_view loses
// the size, and the null-terminator.
{
auto s = span(base::cstring_view("hello"));
static_assert(std::same_as<decltype(s), span<const char>>);
EXPECT_EQ(s[0u], 'h');
EXPECT_EQ(s[1u], 'e');
EXPECT_EQ(s[4u], 'o');
EXPECT_EQ(s.size(), 5u);
} // Includes the terminating null, size known at compile time.
{
auto s = span_with_nul_from_cstring("hello");
static_assert(std::same_as<decltype(s), span<const char, 6u>>);
@ -716,6 +726,17 @@ TEST(SpanTest, FromCString) {
EXPECT_EQ(s[5u], '\0');
}
// Includes the terminating null, from a basic_cstring_view.
{
cstring_view str = "hello";
auto s = span_with_nul_from_cstring_view(str);
static_assert(std::same_as<decltype(s), span<const char>>);
EXPECT_EQ(s[0u], 'h');
EXPECT_EQ(s[1u], 'e');
EXPECT_EQ(s[4u], 'o');
EXPECT_EQ(s[5u], '\0');
}
// No terminating null, size known at compile time. Converted to a span of
// uint8_t bytes.
{
@ -735,6 +756,17 @@ TEST(SpanTest, FromCString) {
EXPECT_EQ(s[4u], 'o');
EXPECT_EQ(s[5u], '\0');
}
// Includes the terminating null, from a basic_cstring_view. Converted to a
// span of uint8_t bytes.
{
cstring_view str = "hello";
auto s = byte_span_with_nul_from_cstring_view(str);
static_assert(std::same_as<decltype(s), span<const uint8_t>>);
EXPECT_EQ(s[0u], 'h');
EXPECT_EQ(s[1u], 'e');
EXPECT_EQ(s[4u], 'o');
EXPECT_EQ(s[5u], '\0');
}
}
TEST(SpanTest, FromCStringEmpty) {