Arene Base
Fundamental Utilities For Safety Critical C++
Loading...
Searching...
No Matches
non_owning_ptr.hpp
Go to the documentation of this file.
1// Copyright 2024, Toyota Motor Corporation
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4///
5/// @file non_owning_ptr.hpp
6/// @brief Defines non_owning_ptr, a checked nullable pointer type.
7///
8// Copyright 2023, Toyota Motor Corporation
9///
10/// This provides the implementation of the facility specified by <a
11/// href="https://stargate.jamacloud.com/perspective.req?docId=4277752&projectId=67">Arene_Eco_System-L5SW-1299</a>
12///
13///
14
15// IWYU pragma: private, include "arene/base/pointer.hpp"
16
17// parasoft-begin-suppress AUTOSAR-A7_1_5-a-2 "Trailing return syntax permitted by A7-1-5 Permit #1 v1.0.0"
18
19#ifndef INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_POINTER_NON_OWNING_PTR_HPP_
20#define INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_POINTER_NON_OWNING_PTR_HPP_
21
22// parasoft-begin-suppress AUTOSAR-A16_2_2-a-2 "Arene Base aggregate headers permitted by A16-2-2 Permit #1"
23#include "arene/base/compare/operators.hpp"
24#include "arene/base/compiler_support/attributes.hpp"
25#include "arene/base/constraints/constraints.hpp"
26#include "arene/base/contracts/contract.hpp"
27#include "arene/base/stdlib_choice/cstddef.hpp"
28#include "arene/base/stdlib_choice/enable_if.hpp"
29#include "arene/base/stdlib_choice/hash.hpp"
30#include "arene/base/stdlib_choice/is_convertible.hpp"
31#include "arene/base/stdlib_choice/is_pointer.hpp"
32#include "arene/base/stdlib_choice/is_reference.hpp"
33#include "arene/base/stdlib_choice/remove_const.hpp"
34#include "arene/base/stdlib_choice/remove_pointer.hpp"
35#include "arene/base/type_traits/is_instantiation_of.hpp"
36// parasoft-end-suppress AUTOSAR-A16_2_2-a-2
37
38// parasoft-begin-suppress CERT_C-EXP37-a-3 "False positive: The rule does not mention naming all parameters"
39
40namespace arene {
41namespace base {
42
43// forward declaration
44template <typename T>
45class non_owning_ptr;
46
47///
48/// @brief Trait that deduces if a type is an @c non_owning_ptr to any type
49///
50/// The test is after removing const and reference qualification
51///
52/// @tparam T The type to test if it is a @c non_owning_ptr
53///
54template <typename T>
55constexpr bool is_non_owning_ptr_v = is_instantiation_of_v<std::remove_const_t<T>, non_owning_ptr>;
56
57// parasoft-begin-suppress AUTOSAR-A14_5_1-a "False positive: non_owning_ptr has a copy constructor"
58// parasoft-begin-suppress AUTOSAR-A12_1_5-a-2 "False positive: Delegating constructors are used"
59///
60/// @brief A non-owning, nullable pointer with nullptr checks on dereference
61///
62/// @tparam T The type pointed to by the pointer.
63///
64/// A @c non_owning_ptr<T> models @c T* with the following differences:
65/// * Dereferencing @c non_owning_ptr<T> has defined behavior: an
66/// @c ARENE_PRECONDITION violation.
67/// * The arithmetic operations are deleted.
68/// * @c delete 'ing the held object through the @c non_owning_ptr is
69/// unsupported.
70///
71template <typename T>
72class non_owning_ptr : full_ordering_operators_from_less_than_and_equals<non_owning_ptr<T>> {
73 // TODO: Decide if this constraint should be retained.
74 static_assert(
75 !std::is_pointer<T>::value,
76 "Cannot create an object pointer to a raw pointer. Perhaps you "
77 "meant non_owning_ptr<T> for T* semantics, or "
78 "non_owning_ptr<non_owning_ptr<T>> for T** semantics?"
79 );
80 static_assert(
81 !std::is_reference<T>::value,
82 "Cannot create an object pointer to a reference. Perhaps you "
83 "meant non_owning_ptr<T> rather than non_owning_ptr<T&>?"
84 );
85
86 // parasoft-begin-suppress AUTOSAR-A2_10_1-e "False positive: Does not hide member of unrelated template"
87 /// @brief Type alias for base class
88 using ordering_base = full_ordering_operators_from_less_than_and_equals<non_owning_ptr<T>>;
89 // parasoft-end-suppress AUTOSAR-A2_10_1-e
90
91 public:
92 // parasoft-begin-suppress AUTOSAR-A2_10_1-d "False positive: 'pointer' does not hide anything"
93 // parasoft-begin-suppress AUTOSAR-A2_10_1-e "False positive: Does not hide member of unrelated template"
94 /// @brief The type of a pointer to @c T.
95 using pointer = T*;
96 // parasoft-end-suppress AUTOSAR-A2_10_1-e
97 // parasoft-end-suppress AUTOSAR-A2_10_1-d
98 // parasoft-begin-suppress AUTOSAR-A2_10_1-e "False positive: Does not hide member of unrelated template"
99 /// @brief The type of the element pointed to.
100 using element_type = T;
101 // parasoft-end-suppress AUTOSAR-A2_10_1-e
102 // parasoft-begin-suppress AUTOSAR-A2_10_1-d "False positive: 'reference' does not hide anything"
103 /// @brief The type of a reference to @c T.
104 using reference = T&;
105 // parasoft-end-suppress AUTOSAR-A2_10_1-d
106
107 ///
108 /// @brief Default, trivial constructor.
109 /// @post Behavior is equivalent to constructing a raw pointer: If explicit,
110 /// @c get() will return nullptr, otherwise the state is undefined.
111 ///
112 constexpr non_owning_ptr() noexcept = default;
113
114 ///
115 /// @brief Constructor from nullptr.
116 /// @post @c get() returns nullptr.
117 ///
118 // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
119 constexpr non_owning_ptr(std::nullptr_t) noexcept
120 : ordering_base{},
121 ptr_(nullptr) {}
122
123 ///
124 /// @brief Constructor from a pointer to T
125 /// @param new_ptr The pointer to hold.
126 /// @post @c get() returns new_ptr
127 ///
128 // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
129 constexpr non_owning_ptr(pointer new_ptr) noexcept
130 : ordering_base{},
131 ptr_(new_ptr) {}
132
133 // parasoft-begin-suppress AUTOSAR-A12_1_1-a "False positive: Base class initialized by delegating constructor
134 ///
135 /// @brief Constructor from non_owning_ptr convertible to the held type.
136 ///
137 /// @tparam U the element type of the @c non_owning_ptr to convert from. Must
138 /// be pointer-convertible to @c pointer.
139 /// @param new_ptr The pointer to hold.
140 /// @post @c get() returns @c new_ptr converted to @c pointer.
141 ///
142 template <
143 typename U = element_type,
144 constraints<std::enable_if_t<std::is_convertible<typename non_owning_ptr<U>::pointer, pointer>::value>> = nullptr>
145 // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
146 constexpr non_owning_ptr(non_owning_ptr<U> new_ptr) noexcept
147 : non_owning_ptr(new_ptr.get()) {}
148
149 ///
150 /// @brief Constructor from a raw pointer convertible to the held type.
151 ///
152 /// @tparam U the pointer type to convert from. Must be convertible to
153 /// @c pointer .
154 /// @param new_ptr The pointer to hold.
155 /// @post @c get() returns @c new_ptr converted to @c pointer .
156 ///
157 template <
158 typename U = pointer,
159 constraints<
160 std::enable_if_t<std::is_pointer<U>::value>,
161 std::enable_if_t<std::is_convertible<U, pointer>::value>> = nullptr>
162 // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
163 constexpr non_owning_ptr(U new_ptr) noexcept
164 : non_owning_ptr(static_cast<pointer>(new_ptr)) {}
165
166 // parasoft-end-suppress AUTOSAR-A12_1_1-a
167
168 ///
169 /// @brief Accesses the held pointer directly
170 ///
171 /// @return pointer The held pointer
172 ///
173 ARENE_NODISCARD constexpr auto get() const noexcept -> pointer { return ptr_; }
174
175 ///
176 /// @brief Resets the held pointer to a new value.
177 ///
178 /// @tparam U the pointer type to convert from. Must be convertible to
179 /// @c pointer .
180 /// @param new_ptr The pointer to reset from. Defaults to <c>nullptr</c>.
181 /// @post @c get() returns @c new_ptr converted to @c pointer .
182 ///
183 template <
184 typename U = pointer,
185 constraints<
186 std::enable_if_t<std::is_pointer<U>::value>,
187 std::enable_if_t<std::is_convertible<U, pointer>::value>> = nullptr>
188 constexpr void reset(U new_ptr = nullptr) {
189 ptr_ = static_cast<pointer>(new_ptr);
190 }
191
192 ///
193 /// @brief Dereference operator
194 ///
195 /// @pre <c>get() != nullptr</c>, otherwise an @c ARENE_PRECONDITION
196 /// violation.
197 /// @return reference_type A reference to the object pointed to
198 ///
199 ARENE_NODISCARD constexpr auto operator*() const noexcept -> reference { return *checked_get(); }
200
201 ///
202 /// @brief Arrow operator
203 ///
204 /// @pre <c>get() != nullptr</c>, otherwise an @c ARENE_PRECONDITION
205 /// violation.
206 /// @return pointer The held pointer
207 ///
208 ARENE_NODISCARD constexpr auto operator->() const noexcept -> pointer { return checked_get(); }
209
210 ///
211 /// @brief Conversion operator to pointer-like type
212 ///
213 /// @tparam U the type to convert to. Must be convertible from
214 /// @c pointer .
215 /// @return U The held pointer, converted to @c U
216 ///
217 template <
218 typename U,
219 constraints<std::enable_if_t<!is_non_owning_ptr_v<U>>, std::enable_if_t<std::is_convertible<pointer, U>::value>> =
220 nullptr>
221 // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
222 constexpr explicit operator U() const noexcept {
223 return {get()};
224 }
225
226 ///
227 /// @brief Conversion to bool.
228 ///
229 /// @return true If <c>get() != nullptr</c>.
230 /// @return false If <c>get() == nullptr</c>.
231 ///
232 // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
233 ARENE_NODISCARD constexpr explicit operator bool() const noexcept { return get() != nullptr; }
234
235 ///
236 /// @brief Boolean negation operator.
237 ///
238 /// @return true If <c>get() == nullptr</c>
239 /// @return false If <c>get() != nullptr</c>
240 ///
241 ARENE_NODISCARD constexpr auto operator!() const noexcept -> bool { return !static_cast<bool>(*this); }
242
243 // parasoft-begin-suppress AUTOSAR-A0_1_3-a-2 "False positive: Function is namespace scope and used in other
244 // translation units"
245 // parasoft-begin-suppress AUTOSAR-A11_3_1-a-2 "False positive: comparison operators are permitted"
246 // parasoft-begin-suppress AUTOSAR-A2_7_3-a-2 "False positive: All overloads are fully are documented"
247 // parasoft-begin-suppress AUTOSAR-A2_7_3-b-2 "False positive: All overloads are fully are documented"
248 /// @brief 6-way comparison is equivalent to comparing raw pointers.
249 /// @param lhs The first value to compare
250 /// @param rhs The second value to compare
251 /// @return The result of the comparison of the underlying pointers
252 /// @{
253 ARENE_NODISCARD friend constexpr auto operator==(non_owning_ptr const& lhs, non_owning_ptr const& rhs) noexcept
254 -> bool {
255 return lhs.get() == rhs.get();
256 }
257
258 ARENE_NODISCARD friend constexpr auto operator<(non_owning_ptr const& lhs, non_owning_ptr const& rhs) noexcept
259 -> bool {
260 return lhs.get() < rhs.get();
261 }
262 /// @}
263 // parasoft-end-suppress AUTOSAR-A2_7_3-b-2
264 // parasoft-end-suppress AUTOSAR-A2_7_3-a-2
265 // parasoft-end-suppress AUTOSAR-A11_3_1-a-2
266 // parasoft-end-suppress AUTOSAR-A0_1_3-a-2
267
268 // parasoft-begin-suppress AUTOSAR-A2_7_3-a-2 "False positive: All overloads are fully are documented"
269 /// @brief Pointer arithmetic is explicitly deleted
270 /// @{
271 template <typename I>
272 constexpr auto operator[](I) = delete;
273 template <typename I>
274 constexpr auto operator[](I) const = delete;
275 template <typename I>
276 constexpr auto operator+(I const&) const -> non_owning_ptr = delete;
277 template <typename I>
278 constexpr auto operator-(I const&) const -> non_owning_ptr = delete;
279 constexpr auto operator++() -> non_owning_ptr& = delete;
280 // parasoft-begin-suppress AUTOSAR-A3_9_1-b-2 "False positive: postincrement requires an int parameter"
281 constexpr auto operator++(int) -> non_owning_ptr& = delete;
282 // parasoft-end-suppress AUTOSAR-A3_9_1-b-2
283 constexpr auto operator--() -> non_owning_ptr& = delete;
284 // parasoft-begin-suppress AUTOSAR-A3_9_1-b-2 "False positive: postdecrement requires an int parameter"
285 constexpr auto operator--(int) -> non_owning_ptr& = delete;
286 // parasoft-end-suppress AUTOSAR-A3_9_1-b-2
287 /// @}
288 // parasoft-end-suppress AUTOSAR-A2_7_3-a-2
289
290 private:
291 ///
292 /// @brief Equivalent to @c get() but with a precondition check
293 /// @pre <c>get() != nullptr</c>, otherwise an @c ARENE_PRECONDITION
294 /// violation.
295 /// @return pointer The held pointer
296 ///
297 ARENE_NODISCARD constexpr auto checked_get() const -> pointer {
298 ARENE_PRECONDITION(ptr_);
299 return ptr_;
300 }
301
302 /// @brief The held pointer
303 pointer ptr_;
304};
305// parasoft-end-suppress AUTOSAR-A12_1_5-a-2
306// parasoft-end-suppress AUTOSAR-A14_5_1-a
307
308///
309/// @brief @c non_owning_ptr factory to allow template deduction.
310///
311/// @tparam T The raw pointer type to construct the @c non_owning_ptr from
312/// @param ptr The pointer to construct the @c non_owning_ptr from.
313/// @return Equivalent to @c non_owning_ptr<std::remove_pointer_t<T>>{ptr}.
314///
315template <typename T, constraints<std::enable_if_t<std::is_pointer<T>::value>> = nullptr>
316ARENE_NODISCARD constexpr auto make_non_owning_ptr(T ptr) noexcept {
318}
319
320} // namespace base
321} // namespace arene
322
323// parasoft-begin-suppress AUTOSAR-A17_6_1-a-2 "False positive: specialization of standard templates is permitted"
324// parasoft-begin-suppress CERT_CPP-DCL58-a-2 "False positive: specialization of standard templates is permitted"
325namespace std {
326// parasoft-begin-suppress AUTOSAR-A11_0_2-a-2 "False positive: must follow the primary template"
327/// @brief @c std::hash specialization for @c non_owning_ptr.
328/// The hash is equivalent to the hash of the underlying pointer.
329///
330template <typename T>
332 /// @brief Calculate the hash of the pointer
333 /// @param ptr The pointer to calculate the hash of
334 /// @return The hash
335 constexpr auto operator()(::arene::base::non_owning_ptr<T> const& ptr) const noexcept -> size_t {
336 return hash<typename arene::base::non_owning_ptr<T>::pointer>()(ptr.get());
337 }
338};
339// parasoft-end-suppress AUTOSAR-A11_0_2-a-2
340
341} // namespace std
342// parasoft-end-suppress CERT_CPP-DCL58-a-2
343// parasoft-end-suppress AUTOSAR-A17_6_1-a-2
344
345#endif // INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_POINTER_NON_OWNING_PTR_HPP_
constexpr auto operator+(I const &) const -> non_owning_ptr=delete
Pointer arithmetic is explicitly deleted.
constexpr auto operator--() -> non_owning_ptr &=delete
Pointer arithmetic is explicitly deleted.
constexpr auto operator++() -> non_owning_ptr &=delete
Pointer arithmetic is explicitly deleted.
constexpr auto operator-(I const &) const -> non_owning_ptr=delete
Pointer arithmetic is explicitly deleted.
constexpr auto operator[](I) const =delete
Pointer arithmetic is explicitly deleted.
constexpr auto operator++(int) -> non_owning_ptr &=delete
Pointer arithmetic is explicitly deleted.
constexpr auto operator--(int) -> non_owning_ptr &=delete
Pointer arithmetic is explicitly deleted.
constexpr non_owning_ptr() noexcept=default
Default, trivial constructor.
Definition array_exceptions_disabled.cpp:11
constexpr bool is_non_owning_ptr_v
Trait that deduces if a type is an non_owning_ptr to any type.
Definition non_owning_ptr.hpp:55
Copyright 2026, Toyota Motor Corporation.
Definition array_exceptions_disabled.cpp:10
constexpr auto operator()(::arene::base::non_owning_ptr< T > const &ptr) const noexcept -> size_t
Calculate the hash of the pointer.
Definition non_owning_ptr.hpp:335
constexpr auto operator()(::arene::base::result< void, E > const &value) const noexcept(noexcept(hash< E >{}(std::declval< E const & >()))) -> std::size_t
Calculate the hash of a result.
Definition result.hpp:1827
hash function primary template
Definition hash.hpp:138