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:

  1. 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.

  2. Add CONFIG_PIGWEED_SPAN=y to the Zephyr project’s configuration, which causes pw_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#

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.

References#

API reference#

See std::span. The pw::span API is designed to match the std::span API.

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 in pw_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.