1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15
16 #include <cstddef>
17 #include <cstdint>
18
19 #include "lib/stdcompat/bit.h"
20 #include "pw_assert/assert.h"
21 #include "pw_bytes/span.h"
22 #include "pw_preprocessor/compiler.h"
23
24 namespace pw {
25
26 /// Returns whether the given pointer meets the given alignment requirement.
IsAlignedAs(const void * ptr,size_t alignment)27 inline bool IsAlignedAs(const void* ptr, size_t alignment) {
28 return (cpp20::bit_cast<uintptr_t>(ptr) % alignment) == 0;
29 }
30
31 /// Returns whether the given pointer meets the alignment requirement for the
32 /// given type.
33 template <typename T>
IsAlignedAs(const void * ptr)34 bool IsAlignedAs(const void* ptr) {
35 return IsAlignedAs(ptr, alignof(T));
36 }
37
38 /// Returns the value rounded down to the nearest multiple of alignment.
AlignDown(uintptr_t value,size_t alignment)39 constexpr size_t AlignDown(uintptr_t value, size_t alignment) {
40 PW_ASSERT(!PW_MUL_OVERFLOW((value / alignment), alignment, &value));
41 return value;
42 }
43
44 /// Returns the value rounded down to the nearest multiple of alignment.
45 template <typename T>
AlignDown(T * value,size_t alignment)46 constexpr T* AlignDown(T* value, size_t alignment) {
47 return reinterpret_cast<T*>(
48 AlignDown(reinterpret_cast<uintptr_t>(value), alignment));
49 }
50
51 /// Returns the value rounded up to the nearest multiple of alignment.
AlignUp(uintptr_t value,size_t alignment)52 constexpr size_t AlignUp(uintptr_t value, size_t alignment) {
53 PW_ASSERT(!PW_ADD_OVERFLOW(value, alignment - 1, &value));
54 return AlignDown(value, alignment);
55 }
56
57 /// Returns the value rounded up to the nearest multiple of alignment.
58 template <typename T>
AlignUp(T * value,size_t alignment)59 constexpr T* AlignUp(T* value, size_t alignment) {
60 return reinterpret_cast<T*>(
61 AlignUp(reinterpret_cast<uintptr_t>(value), alignment));
62 }
63
64 /// Returns the number of padding bytes required to align the provided length.
Padding(size_t length,size_t alignment)65 constexpr size_t Padding(size_t length, size_t alignment) {
66 return AlignUp(length, alignment) - length;
67 }
68
69 /// Returns the largest aligned subspan of a given byte span.
70 ///
71 /// The subspan will start and end on alignment boundaries.
72 ///
73 /// @returns A `ByteSpan` within `bytes` aligned to `alignment`, or an empty
74 /// `ByteSpan` if alignment was not possible.
75 ByteSpan GetAlignedSubspan(ByteSpan bytes, size_t alignment);
76
77 } // namespace pw
78