C/C++ API Reference
Loading...
Searching...
No Matches
packed_ptr.h
1// Copyright 2024 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
22namespace pw {
23
25
34template <typename T>
35class PackedPtr {
36 public:
37 // Calculate the number of available bits in a function, since the type T may
38 // include fields of type `PackedPtr<T>` and not be fully defined when the
39 // `PackedPtr<T>` class is instantiated.
40 static constexpr size_t NumBits() {
41 CheckAlignment();
42 return 31 - cpp20::countl_zero(static_cast<uint32_t>(alignof(T)));
43 }
44
45 constexpr explicit PackedPtr() { CheckAlignment(); }
46 ~PackedPtr() = default;
47
48 constexpr PackedPtr(T* ptr, uintptr_t packed_value) : PackedPtr() {
49 set(ptr);
51 }
52
53 template <typename T2,
54 typename = std::enable_if_t<std::is_convertible_v<T2, T>>>
55 constexpr PackedPtr(const PackedPtr<T2>& other) {
56 *this = other;
57 }
58
59 template <typename T2,
60 typename = std::enable_if_t<std::is_convertible_v<T2, T>>>
61 constexpr PackedPtr& operator=(const PackedPtr<T2>& other) {
62 data_ = other.data_;
63 return *this;
64 }
65
66 template <typename T2,
67 typename = std::enable_if_t<std::is_convertible_v<T2, T>>>
68 constexpr PackedPtr(PackedPtr<T2>&& other) {
69 *this = std::move(other);
70 }
71
72 template <typename T2,
73 typename = std::enable_if_t<std::is_convertible_v<T2, T>>>
74 constexpr PackedPtr& operator=(PackedPtr<T2>&& other) {
75 data_ = std::exchange(other.data_, 0);
76 return *this;
77 }
78
79 constexpr T& operator*() const { return *(get()); }
80 constexpr T* operator->() const { return get(); }
81
83 constexpr T* get() const { return cpp20::bit_cast<T*>(data_ & ~kValueMask); }
84
86 constexpr uintptr_t packed_value() const { return data_ & kValueMask; }
87
89 constexpr void set(T* ptr) {
90 auto packed_ptr = cpp20::bit_cast<uintptr_t, T*>(ptr);
91 PW_DASSERT((packed_ptr & kValueMask) == 0);
92 data_ = packed_ptr | packed_value();
93 }
94
98 constexpr void set_packed_value(uintptr_t packed_value) {
99 PW_DASSERT(packed_value <= kValueMask);
100 data_ = (data_ & ~kValueMask) | packed_value;
101 }
102
103 private:
104 // Check the alignment of T in a function, since the type T may include fields
105 // of type `PackedPtr<T>` and not be fully defined when the `PackedPtr<T>`
106 // class is instantiated.
107 static constexpr void CheckAlignment() {
108 static_assert(alignof(T) > 1,
109 "Alignment must be more than one to pack any bits");
110 }
111
112 static constexpr uintptr_t kValueMask = (1 << NumBits()) - 1;
113
114 // Allows copying and moving between convertible types.
115 template <typename>
116 friend class PackedPtr;
117
118 uintptr_t data_ = 0;
119};
120
122
123} // namespace pw
Definition: packed_ptr.h:35
constexpr void set_packed_value(uintptr_t packed_value)
Definition: packed_ptr.h:98
constexpr void set(T *ptr)
Sets the pointer without changing the packed value.
Definition: packed_ptr.h:89
constexpr uintptr_t packed_value() const
Returns the packed_value packed into the unused bits of the pointer.
Definition: packed_ptr.h:86
constexpr T * get() const
Returns the pointer.
Definition: packed_ptr.h:83
The Pigweed namespace.
Definition: alignment.h:27