Skip to content

Commit

Permalink
pw_bytes: Add utility for checking alignment
Browse files Browse the repository at this point in the history
Change-Id: I539ac0155c1aa5a4991b59727917e7dd6d018157
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/248192
Docs-Not-Needed: Aaron Green <[email protected]>
Lint: Lint 🤖 <[email protected]>
Commit-Queue: Aaron Green <[email protected]>
Reviewed-by: Taylor Cramer <[email protected]>
  • Loading branch information
nopsledder authored and CQ Bot Account committed Nov 18, 2024
1 parent 48712ad commit a287811
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 6 deletions.
1 change: 1 addition & 0 deletions pw_bytes/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ cc_library(
"//pw_assert",
"//pw_bytes",
"//pw_preprocessor",
"//third_party/fuchsia:stdcompat",
],
)

Expand Down
1 change: 1 addition & 0 deletions pw_bytes/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ pw_source_set("alignment") {
public = [ "public/pw_bytes/alignment.h" ]
public_deps = [
":pw_bytes",
"$dir_pw_third_party/fuchsia:stdcompat",
dir_pw_assert,
dir_pw_preprocessor,
]
Expand Down
1 change: 1 addition & 0 deletions pw_bytes/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ pw_add_library(pw_bytes.alignment STATIC
pw_assert
pw_bytes
pw_preprocessor
pw_third_party.fuchsia.stdcompat
SOURCES
alignment.cc
)
Expand Down
29 changes: 29 additions & 0 deletions pw_bytes/alignment_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,40 @@

#include "pw_bytes/alignment.h"

#include "lib/stdcompat/bit.h"
#include "pw_unit_test/framework.h"

namespace pw {
namespace {

template <typename T>
void TestIsAlignedAs() {
T t{};
auto* ptr = reinterpret_cast<const std::byte*>(&t);
EXPECT_TRUE(IsAlignedAs<T>(&t));
if constexpr (alignof(T) != 1U) {
EXPECT_FALSE(IsAlignedAs<T>(ptr + 1));
EXPECT_FALSE(IsAlignedAs<T>(ptr + alignof(T) - 1));
}
EXPECT_TRUE(IsAlignedAs<T>(ptr + alignof(T)));
}

TEST(IsAlignedAs, Scalar) {
TestIsAlignedAs<int8_t>();
TestIsAlignedAs<uint16_t>();
TestIsAlignedAs<int32_t>();
TestIsAlignedAs<size_t>();
TestIsAlignedAs<intptr_t>();
}

TEST(IsAlignedAs, Object) {
struct Foo {
uint8_t a;
uint16_t b;
};
TestIsAlignedAs<Foo>();
}

TEST(AlignUp, Zero) {
EXPECT_EQ(0u, AlignUp(0, 1));
EXPECT_EQ(0u, AlignUp(0, 2));
Expand Down
8 changes: 6 additions & 2 deletions pw_bytes/docs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,15 @@ pw_bytes/alignment.h
====================
Functions for aligning sizes and addresses to memory alignment boundaries.

.. doxygenfunction:: pw::AlignDown(size_t value, size_t alignment)
.. doxygenfunction:: pw::IsAlignedAs(const void* ptr, size_t alignment)

.. doxygenfunction:: pw::IsAlignedAs(const void* ptr)

.. doxygenfunction:: pw::AlignDown(uintptr_t value, size_t alignment)

.. doxygenfunction:: pw::AlignDown(T* value, size_t alignment)

.. doxygenfunction:: pw::AlignUp(size_t value, size_t alignment)
.. doxygenfunction:: pw::AlignUp(uintptr_t value, size_t alignment)

.. doxygenfunction:: pw::AlignUp(T* value, size_t alignment)

Expand Down
22 changes: 18 additions & 4 deletions pw_bytes/public/pw_bytes/alignment.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,29 @@
#pragma once

#include <cstddef>
#include <cstdint>

#include "lib/stdcompat/bit.h"
#include "pw_assert/assert.h"
#include "pw_bytes/span.h"
#include "pw_preprocessor/compiler.h"

namespace pw {

/// Returns whether the given pointer meets the given alignment requirement.
inline bool IsAlignedAs(const void* ptr, size_t alignment) {
return (cpp20::bit_cast<uintptr_t>(ptr) % alignment) == 0;
}

/// Returns whether the given pointer meets the alignment requirement for the
/// given type.
template <typename T>
bool IsAlignedAs(const void* ptr) {
return IsAlignedAs(ptr, alignof(T));
}

/// Returns the value rounded down to the nearest multiple of alignment.
constexpr size_t AlignDown(size_t value, size_t alignment) {
constexpr size_t AlignDown(uintptr_t value, size_t alignment) {
PW_ASSERT(!PW_MUL_OVERFLOW((value / alignment), alignment, &value));
return value;
}
Expand All @@ -31,11 +45,11 @@ constexpr size_t AlignDown(size_t value, size_t alignment) {
template <typename T>
constexpr T* AlignDown(T* value, size_t alignment) {
return reinterpret_cast<T*>(
AlignDown(reinterpret_cast<size_t>(value), alignment));
AlignDown(reinterpret_cast<uintptr_t>(value), alignment));
}

/// Returns the value rounded up to the nearest multiple of alignment.
constexpr size_t AlignUp(size_t value, size_t alignment) {
constexpr size_t AlignUp(uintptr_t value, size_t alignment) {
PW_ASSERT(!PW_ADD_OVERFLOW(value, alignment - 1, &value));
return AlignDown(value, alignment);
}
Expand All @@ -44,7 +58,7 @@ constexpr size_t AlignUp(size_t value, size_t alignment) {
template <typename T>
constexpr T* AlignUp(T* value, size_t alignment) {
return reinterpret_cast<T*>(
AlignUp(reinterpret_cast<size_t>(value), alignment));
AlignUp(reinterpret_cast<uintptr_t>(value), alignment));
}

/// Returns the number of padding bytes required to align the provided length.
Expand Down

0 comments on commit a287811

Please sign in to comment.