pw_alignment#

Natural object alignment, guaranteed

Stable C++17

  • Transparent: Enforce natural alignment without any changes to how your objects are used.

  • Efficient: Prevent your compiler from emitting libcalls to builtin atomic functions and ensure it uses native atomic instructions instead.

#include "pw_alignment/alignment.h"

// Passing a `std::optional<bool>` to `__atomic_exchange` might not replace
// the call with native instructions if the compiler cannot determine all
// instances of this object will happen to be aligned.
std::atomic<std::optional<bool>> maybe_nat_aligned_obj;

// `pw::NaturallyAligned<...>` forces the object to be aligned to its size,
// so passing it to `__atomic_exchange` will result in a replacement with
// native instructions.
std::atomic<pw::NaturallyAligned<std::optional<bool>>> nat_aligned_obj;

// Shorter spelling for the same as above.
pw::AlignedAtomic<std::optional<bool>> also_nat_aligned_obj;

pw_alignment portably ensures that your compiler uses native atomic instructions rather than libcalls to builtin atomic functions. Take for example std::atomic<std::optional<bool>>. Accessing the underlying object normally involves a call to a builtin __atomic_* function. The problem is that the compiler sometimes can’t determine that the size of the object is the same as the size of its alignment. pw_alignment ensures that an object aligns to its size so that compilers can always make this optimization.

Warning

Using std::optional<bool> is only a workaround that may not work with all compilers. This specifically does not work when targetting ARM cortex M0. Additionally, std::optional<bool> is not the recommended way to represent a ternary variable.

Get Started

How to set up pw_alignment in your build system.

API Reference

Reference information about the pw_alignment API.

Get started#

Add @pigweed//pw_alignment to the deps list in your Bazel target:

cc_library("...") {
  # ...
  deps = [
    # ...
    "@pigweed//pw_alignment",
    # ...
  ]
}

This assumes that your Bazel WORKSPACE has a repository named @pigweed that points to the upstream Pigweed repository.

Add $dir_pw_alignment to the deps list in your pw_executable() build target:

pw_executable("...") {
  # ...
  deps = [
    # ...
    "$dir_pw_alignment",
    # ...
  ]
}

Add pw_alignment to your pw_add_library or similar CMake target:

pw_add_library(my_library STATIC
  HEADERS
    ...
  PRIVATE_DEPS
    # ...
    pw_alignment
    # ...
)

API reference#

group pw_alignment

Typedefs

template<typename T>
using AlignedAtomic = std::atomic<NaturallyAligned<T>>#

Ensures the object held by std::atomic is naturally aligned. This enables the compiler to replace libcalls to atomic functions with native instructions when appropriate. AlignedAtomic is a convenience wrapper.

Example:

#include "pw_alignment/alignment.h"

pw::AlignedAtomic<std::optional<bool>> mute_enable{};

std::optional<bool> has a size of 2 but alignment of 1, which would normally lower to an __atomic_* libcall, but pw::NaturallyAligned in std::atomic tells the compiler to align the object to 2 bytes, which satisfies the requirements for replacing __atomic_* with native instructions.

template<typename T>
struct NaturallyAligned : public T#

Ensures the object is naturally aligned to a power of 2 bytes greater than or equal to its size. NaturallyAligned is a wrapper class.

Example:

#include "pw_alignment/alignment.h"

std::atomic<pw::NaturallyAligned<std::optional<bool>>> nat_aligned_obj;