pw_span#
std::span for C++17
Stable C++17 C++20
Standardized:
pw::span
matches C++20’s std::span as closely as possible.Zero-cost: If
std::span
is available,pw::span
is simply an alias of it.
#include <span>
// With pw::span, a buffer is passed as a single argument.
// No need to handle pointer and size arguments.
bool ProcessBuffer(pw::span<uint8_t> buffer);
bool DoStuff() {
// ...
ProcessBuffer(c_array);
ProcessBuffer(array_object);
ProcessBuffer(pw::span(data_pointer, data_size));
}
pw::span
is a convenient abstraction that wraps a pointer and a
size. It’s especially useful in APIs. Spans support implicit conversions from
C arrays, std::array
, or any STL-style container, such as
std::string_view
.
Get started#
Add @pigweed//pw_span
to the deps
list in your Bazel target:
cc_library("...") {
# ...
deps = [
# ...
"@pigweed//pw_span",
# ...
]
}
This assumes that your Bazel WORKSPACE
has a repository named @pigweed
that points to the upstream Pigweed repository.
Add $dir_pw_span
to the deps
list in your pw_executable()
build target:
pw_executable("...") {
# ...
deps = [
# ...
"$dir_pw_span",
# ...
]
}
Add pw_span
to your pw_add_library
or similar CMake target:
pw_add_library(my_library STATIC
HEADERS
...
PRIVATE_DEPS
# ...
pw_span
# ...
)
There are two ways to use pw_span
from a Zephyr project:
Depend on
pw_span
in your CMake target (see CMake tab). This is Pigweed Team’s suggested approach since it enables precise CMake dependency analysis.Add
CONFIG_PIGWEED_SPAN=y
to the Zephyr project’s configuration, which causespw_span
to become a global dependency and have the includes exposed to all targets. Pigweed team does not recommend this approach, though it is the typical Zephyr solution.
Guides#
pw::span
as a function parameter#
pw::span
objects should be passed by value.
Yes: Accept pw::span
object by value:
bool ProcessBuffer(pw::span<uint8_t> buffer);
No: Accept pw::span
object by reference:
bool ProcessBuffer(const pw::span<uint8_t>& buffer);
Rationale: Since a pw::span
object is essentially a pointer and a size,
references to pw::span
objects are almost always unnecessary indirection.
Operating on arrays of bytes#
When operating on an array of bytes you typically need pointer and size arguments:
bool ProcessBuffer(char* buffer, size_t buffer_size);
bool DoStuff() {
ProcessBuffer(c_array, sizeof(c_array));
ProcessBuffer(array_object.data(), array_object.size());
ProcessBuffer(data_pointer, data_size);
}
With pw::span
you can pass the buffer as a single argument instead:
#include <span>
// With pw::span, a buffer is passed as a single argument.
// No need to handle pointer and size arguments.
bool ProcessBuffer(pw::span<uint8_t> buffer);
bool DoStuff() {
// ...
ProcessBuffer(c_array);
ProcessBuffer(array_object);
ProcessBuffer(pw::span(data_pointer, data_size));
}
Working with spans of binary data#
Use pw::span<std::byte>
or pw::span<const std::byte>
to represent
spans of binary data. Convert spans to byte spans with pw::as_bytes
or
pw::as_writable_bytes
.
void ProcessData(pw::span<const std::byte> data);
void DoStuff() {
std::array<AnyType, 7> data = { ... };
ProcessData(pw::as_bytes(pw::span(data)));
}
pw_bytes/span.h
provides ByteSpan
and ConstByteSpan
aliases for
these types.
Convert byte spans back to their original type, or to spans of other 1-byte
types using pw::span_cast<T>
.
#include "pw_bytes/span.h"
#include "pw_span/cast.h"
void SDK_ReadData(uint8_t* data, size_t size);
void SDK_WriteData(const uint8_t* data, size_t size);
void Write(pw::ConstByteSpan buffer) {
auto data = pw::span_cast<const uint8_t>(buffer);
SDK_WriteData(data.data(), data.size());
}
void Read(pw::ByteSpan buffer) {
auto data = pw::span_cast<uint8_t>(buffer);
SDK_ReadData(data.data(), data.size());
}
Warning
pw::span_cast<T>
is only safe to use if the underlying data is actually
of the specified type, or if T
is another 1-byte type (e.g.
uint8_t
). You cannot safely use this function to reinterpret e.g. a raw
byte array from malloc()
as a span of integers.
References#
pw_span/span.h#
See std::span.
The pw::span
API is designed to match the std::span
API.
pw_span/cast.h#
This header provides functions for casting between pw::span
types, and is
not part of the std::span
interface.
-
span<T> pw::span_cast(std::span<std::byte> bytes)#
Casts a
pw::span<std::byte>
(ByteSpan
) to a span of a different type.This function is only safe to use if the underlying data is actually of the specified type. You cannot safely use this function to reinterpret e.g. a raw byte array from
malloc()
as a span of integers.This function is essentially the inverse of
pw::as_writable_bytes
.If
kSourceExtentBytes
isdynamic_extent
, the returned span also has a dynamic extent. Otherwise, the returned span has a static extent ofkSourceExtentBytes / sizeof(ResultT)
.
-
span<const T> pw::span_cast(std::span<const std::byte> bytes)#
Casts a
pw::span<const std::byte>
(ConstByteSpan
) to a span of a different const type.This function is only safe to use if the underlying data is actually of the specified type. You cannot safely use this function to reinterpret e.g. a raw byte array from
malloc()
as a span of integers.This function is essentially the inverse of
pw::as_bytes
.If
kSourceExtentBytes
isdynamic_extent
, the returned span also has a dynamic extent. Otherwise, the returned span has a static extent ofkSourceExtentBytes / sizeof(ResultT)
.
Configuration options#
The following configurations can be adjusted via compile-time configuration of this module, see the module documentation for more details.
-
PW_SPAN_ENABLE_ASSERTS#
Controls whether
pw_span
includes asserts for detecting disallowed span operations at runtime.For C++20 and later, this replaces
std::span
with the custom implementation inpw_span
to ensure bounds-checking asserts have been enabled.This defaults to disabled because of the significant increase in code size caused by enabling this feature. It’s strongly recommended to enable this in debug and testing builds.