xref: /aosp_15_r20/external/pigweed/pw_bytes/public/pw_bytes/alignment.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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