Arene Base
Fundamental Utilities For Safety Critical C++
Loading...
Searching...
No Matches
non_null.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#ifndef INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_POINTER_NON_NULL_HPP_
6#define INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_POINTER_NON_NULL_HPP_
7
8// IWYU pragma: private, include "arene/base/pointer.hpp"
9
10// parasoft-begin-suppress AUTOSAR-A7_1_5-a-2 "Trailing return syntax permitted by A7-1-5 Permit #1 v1.0.0"
11
12// parasoft-begin-suppress AUTOSAR-A16_2_2-a-2 "Arene Base aggregate headers permitted by A16-2-2 Permit #1"
13#include "arene/base/compare/compare_three_way.hpp"
14#include "arene/base/compare/operators.hpp"
15#include "arene/base/compare/strong_ordering.hpp"
16#include "arene/base/compiler_support/attributes.hpp"
17#include "arene/base/constraints/constraints.hpp"
18#include "arene/base/contracts/contract.hpp"
19#include "arene/base/pointer/detail/to_address.hpp"
20#include "arene/base/pointer/detail/type_traits.hpp"
21#include "arene/base/stdlib_choice/cstddef.hpp"
22#include "arene/base/stdlib_choice/decay.hpp"
23#include "arene/base/stdlib_choice/declval.hpp"
24#include "arene/base/stdlib_choice/enable_if.hpp"
25#include "arene/base/stdlib_choice/forward.hpp"
26#include "arene/base/stdlib_choice/hash.hpp"
27#include "arene/base/stdlib_choice/ignore.hpp"
28#include "arene/base/stdlib_choice/is_assignable.hpp"
29#include "arene/base/stdlib_choice/is_constructible.hpp"
30#include "arene/base/stdlib_choice/is_pointer.hpp"
31#include "arene/base/stdlib_choice/is_same.hpp"
32#include "arene/base/stdlib_choice/move.hpp"
33#include "arene/base/stdlib_choice/pointer_traits.hpp"
34#include "arene/base/stdlib_choice/remove_cv.hpp"
35#include "arene/base/type_traits/comparison_traits.hpp"
36#include "arene/base/type_traits/is_instantiation_of.hpp"
37#include "arene/base/type_traits/is_swappable.hpp"
38#include "arene/base/type_traits/remove_cvref.hpp"
39#include "arene/base/utility/swap.hpp"
40// parasoft-end-suppress AUTOSAR-A16_2_2-a-2
41
42// parasoft-begin-suppress CERT_C-EXP37-a-3 "False positive: The rule does not mention naming all parameters"
43
44namespace arene {
45namespace base {
46
47// forward declaration
48template <typename P>
49class non_null;
50
51///
52/// @brief Trait that deduces if a type is an @c non_null to any type
53///
54/// The test is after removing const and reference qualification
55///
56/// @tparam T The type to test if it is a @c non_null
57///
58template <typename T>
60
61namespace operators_detail {
62/// @brief Type trait to check if we can provide a reversed operator== for this pair of types (breaks an infinite loop)
63///
64/// The @c non_null template already provides the reversed operators
65///
66/// @tparam Self The pointee type of the @c non_null instance which is inheriting from this operator mixin
67/// @tparam Other The pointer type of the @c non_null instance which we're trying to compare with (the LHS of a
68/// *reversed* comparison)
69template <typename Self, typename Other>
70constexpr bool eligible_for_reversed_equals_with_v<non_null<Self>, non_null<Other>> = false;
71} // namespace operators_detail
72
73// parasoft-begin-suppress AUTOSAR-A12_1_5-a-2 "False positive: No duplication between constructors"
74///
75/// @brief A pointer type which is never @c nullptr
76///
77/// @tparam P The type of the pointer to wrap.
78///
79/// A wrapper type around a "pointer type" which maintains the invariant that the pointer never be @c nullptr . It is
80/// considered a "malformed program" to attempt to construct a @c non_null with a pointer which is @c nullptr , and thus
81/// an @c ARENE_PRECONDITION violation.
82///
83/// @c non_null<P> models the wrapped pointer type. This means the following properties are true:
84/// - It is copyable if the wrapped pointer is copyable.
85/// - It is movable if the wrapped pointer is movable.
86/// - It is implicitly convertible to (a reference to) the wrapped pointer.
87/// - It is 6-way comparable with the same semantics as the wrapped pointer.
88/// - The dereference/arrow operators are equivalent to dereferencing the
89/// wrapped pointer.
90/// - Calling @c get() is equivalent to calling @c get() on the wrapped pointer if the wrapped pointer is a smart
91/// pointer. See non_null<P>::get() for details.
92/// - Calling @c reset() is equivalent to calling @c reset() on the wrapped pointer, if the wrapped pointer is a smart
93/// pointer. See non_null<P>::reset() for details.
94///
95/// To maintain the invariant that the pointer is never @c nullptr , it is not possible to obtain a non-const lvalue
96/// reference to the wrapped pointer. If @c P is not a raw pointer, it is possible to obtain an rvalue reference to the
97/// wrapped pointer via @c unwrap()&& or by casting from an rvalue-qualified @c non_null .
98///
99/// @warning In order to be useful in real programs, a moved-from @c non_null which contains anything other than a raw
100/// pointer may become @c nullptr . Thus the only valid operations which may be performed on a moved-from @c non_null is
101/// to either assign/reset it to a new value, or let it be destroyed.
102///
103template <typename P>
104class non_null : generic_ordering_from_three_way_compare_and_equals<non_null<P>> {
105 static_assert(pointer::detail::is_pointer_like_v<P>, "non_null is only defined for pointer-like types.");
106
107 /// @brief Type alias for base class
108 using ordering_base = generic_ordering_from_three_way_compare_and_equals<non_null<P>>;
109
110 public:
111 /// @brief The pointer type being wrapped by the @c non_null .
112 using held_pointer = P;
113 /// @brief The type of the element pointed to.
114 using element_type = typename std::pointer_traits<held_pointer>::element_type;
115 // parasoft-begin-suppress AUTOSAR-A2_10_1-d "False positive: 'pointer' does not hide anything"
116 /// @brief The type of a raw pointer to the element pointed to by the @c non_null .
117 using pointer = decltype(::arene::base::pointer::detail::to_address(std::declval<held_pointer>()));
118 // parasoft-end-suppress AUTOSAR-A2_10_1-d
119
120 /// @brief @c non_null cannot be default constructed
121 constexpr non_null() = delete;
122 /// @brief @c non_null cannot be constructed from a literal @c nullptr .
123 constexpr explicit non_null(std::nullptr_t) = delete;
124
125 // parasoft-begin-suppress AUTOSAR-A13_3_1-a-2 "False positive: No forwarding reference"
126 /// @brief Default copy constructor
127 constexpr non_null(non_null const&) = default;
128 /// @brief Default move constructor
129 constexpr non_null(non_null&&) = default;
130 // parasoft-end-suppress AUTOSAR-A13_3_1-a-2
131 // parasoft-begin-suppress AUTOSAR-A13_3_1-a-2 "False positive: No forwarding reference"
132 /// @brief Default copy assignment
133 constexpr auto operator=(non_null const&) -> non_null& = default;
134 /// @brief Default move assignment
135 constexpr auto operator=(non_null&&) -> non_null& = default;
136 // parasoft-end-suppress AUTOSAR-A13_3_1-a-2
137
138 /// @brief Default destructor
139 ~non_null() = default;
140
141 ///
142 /// @brief Construction from a pointer type
143 ///
144 /// @tparam U The type of the pointer to construct from. Must be @c convertible to @c held_pointer
145 /// @param ptr_value The pointer to construct from.
146 /// @pre @c ptr_value must not be @c nullptr , or else @c ARENE_PRECONDITION violation.
147 /// @post @c get() will return a pointer to the element pointed to by @c ptr_value .
148 ///
149 template <
150 typename U,
151 constraints<
152 std::enable_if_t<!is_non_null_v<U>, std::enable_if_t<std::is_constructible<held_pointer, U>::value>>> =
153 nullptr>
154 // NOLINTNEXTLINE(bugprone-forwarding-reference-overload) The check cannot see through constraints.
155 constexpr explicit non_null(U&& ptr_value) noexcept(std::is_nothrow_constructible<held_pointer, U>::value)
156 : ordering_base{},
157 ptr_(std::forward<U>(ptr_value)) {
158 ARENE_PRECONDITION(ptr_ != nullptr);
159 }
160
161 // parasoft-begin-suppress AUTOSAR-A13_3_1-a-2 "False positive: Constrained via SFINAE"
162 ///
163 /// @brief Copy constructor from @c non_null
164 ///
165 /// @tparam U Type of the held pointer of the @c non_null to copy
166 /// @param copy_from The @c non_null to copy
167 ///
168 template <
169 typename U = held_pointer,
170 constraints<std::enable_if_t<std::is_constructible<held_pointer, U const&>::value>> = nullptr>
171 // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) The check can't tell this is a copy ctor
172 constexpr non_null(non_null<U> const& copy_from) noexcept(std::is_nothrow_constructible<held_pointer, U const&>::value
173 )
174 : ordering_base{},
175 ptr_(copy_from.unwrap()) {}
176 // parasoft-end-suppress AUTOSAR-A13_3_1-a-2
177
178 ///
179 /// @brief Move constructor from @c non_null
180 ///
181 /// @tparam U Type of the held pointer of the @c non_null to move
182 /// @param move_from The @c non_null to move
183 ///
184 template <
185 typename U = held_pointer,
186 constraints<std::enable_if_t<std::is_constructible<held_pointer, U&&>::value>> = nullptr>
187 // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions) The check can't tell this a move ctor
188 constexpr non_null(non_null<U>&& move_from) noexcept(std::is_nothrow_constructible<held_pointer, U&&>::value)
189 : ordering_base{},
190 ptr_(std::move(move_from).unwrap()) {}
191
192 ///
193 /// @brief Assignment from a pointer type
194 ///
195 /// @tparam U The type of the pointer to assign from. Must be @c assignable to @c held_pointer
196 /// @param new_ptr The pointer to assign from.
197 /// @pre @c new_ptr must not be @c nullptr , or else @c ARENE_PRECONDITION violation.
198 ///
199 template <
200 typename U = held_pointer,
201 constraints<std::enable_if_t<!is_non_null_v<U>>, std::enable_if_t<std::is_assignable<held_pointer&, U>::value>> =
202 nullptr>
203 constexpr auto operator=(U&& new_ptr) noexcept(std::is_nothrow_assignable<held_pointer&, U>::value) -> non_null& {
204 ARENE_PRECONDITION(new_ptr != nullptr);
205 ptr_ = std::forward<U>(new_ptr);
206 return *this;
207 }
208
209 // parasoft-begin-suppress AUTOSAR-A13_3_1-a-2 "Constrained via SFINAE, permitted by A13-3-1 Permit #1"
210 ///
211 /// @brief Copy assignment from @c non_null
212 ///
213 /// @tparam U Type of the held pointer of the @c non_null to copy. Must be @c assignable to @c held_pointer .
214 /// @param copy_from The @c non_null to copy
215 ///
216 template <
217 typename U = held_pointer,
218 constraints<std::enable_if_t<std::is_assignable<held_pointer&, U const&>::value>> = nullptr>
219 constexpr auto operator=(non_null<U> const& copy_from
220 ) noexcept(std::is_nothrow_assignable<held_pointer&, U const&>::value) -> non_null& {
221 ptr_ = copy_from.unwrap();
222 return *this;
223 }
224 // parasoft-end-suppress AUTOSAR-A13_3_1-a-2
225
226 ///
227 /// @brief Move assignment from @c non_null
228 ///
229 /// @tparam U Type of the held pointer of the @c non_null to move. Must be @c assignable to @c held_pointer .
230 /// @param move_from The @c non_null to move
231 ///
232 template <
233 typename U = held_pointer,
234 constraints<std::enable_if_t<std::is_assignable<held_pointer&, U&&>::value>> = nullptr>
235 constexpr auto operator=(non_null<U>&& move_from) noexcept(std::is_nothrow_assignable<held_pointer&, U&&>::value)
236 -> non_null& {
237 ptr_ = std::move(move_from.unwrap());
238 return *this;
239 }
240
241 // parasoft-begin-suppress AUTOSAR-A2_7_3-a-2 "False positive: All overloads are fully are documented"
242 // parasoft-begin-suppress AUTOSAR-A2_7_3-b-2 "False positive: All overloads are fully are documented"
243 ///
244 /// @brief Gets a pointer to the pointed-to element
245 /// @return pointer A pointer to the pointed-to element. The type is
246 /// @c pointer .
247 /// @invariant The returned pointer will never be equal to @c nullptr .
248 ///
249 /// Behavior is as if @c non_null<P> models @c P . This means that:
250 /// - If @c P is a raw pointer, then returns the pointer.
251 /// - If @c P is a "smart" pointer, then forwards the return from calling
252 /// @c get() on the smart pointer.
253 /// Examples:
254 /// @code{cpp}
255 /// decltype(non_null<int*>.get()) == int*;
256 /// decltype(non_null<std::unique_ptr<int*>>.get()) == int*;
257 /// @endcode
258 ///
259 /// @{
260 template <typename U = held_pointer, constraints<std::enable_if_t<std::is_pointer<U>::value>> = nullptr>
261 ARENE_NODISCARD constexpr auto get() const noexcept -> held_pointer {
262 // A raw pointer can never become null as we can't move from it, so we don't need to check the invariant
263 return ptr_;
264 }
265 template <typename U = held_pointer, constraints<std::enable_if_t<!std::is_pointer<U>::value>> = nullptr>
266 ARENE_NODISCARD constexpr auto get() const noexcept -> decltype(auto) {
267 // A fancy pointer can become null if used-after-move, so we have to check
268 ARENE_INVARIANT(ptr_ != nullptr);
269 return ::arene::base::pointer::detail::to_address(ptr_);
270 }
271 /// @}
272 // parasoft-end-suppress AUTOSAR-A2_7_3-a-2
273 // parasoft-end-suppress AUTOSAR-A2_7_3-b-2
274
275 // parasoft-begin-suppress AUTOSAR-A2_7_3-a-2 "False positive: All overloads are fully are documented"
276 // parasoft-begin-suppress AUTOSAR-A2_7_3-b-2 "False positive: All overloads are fully are documented"
277 ///
278 /// @brief Gets the held pointer backing the @c non_null
279 ///
280 /// @return A reference to the underlying pointer.
281 /// @{
282 // parasoft-begin-suppress AUTOSAR-A9_3_1-a-2 "False positive: returns const reference"
283 // parasoft-begin-suppress AUTOSAR-M9_3_1-a-2 "False positive: returns const reference"
284 ARENE_NODISCARD constexpr auto unwrap() const& noexcept -> held_pointer const& { return ptr_; }
285 // parasoft-end-suppress AUTOSAR-A9_3_1-a-2
286 // parasoft-end-suppress AUTOSAR-M9_3_1-a-2
287
288 template <typename U = held_pointer, constraints<std::enable_if_t<!std::is_pointer<U>::value>> = nullptr>
289 ARENE_NODISCARD constexpr auto unwrap() && noexcept -> held_pointer&& {
290 return std::move(ptr_);
291 }
292 /// @}
293 // parasoft-end-suppress AUTOSAR-A2_7_3-a-2
294 // parasoft-end-suppress AUTOSAR-A2_7_3-b-2
295
296 ///
297 /// @brief Re-assigns the @c non_null to a new held pointer.
298 ///
299 /// The reset is performed using @c held_pointer::reset() .
300 ///
301 /// @tparam U The type of pointer to rest with. Must be valid to call @c held_pointer::rest(U) .
302 /// @param reset_to The pointer to reset the @c non_null to.
303 /// @pre @c ptr must not be @c nullptr , or else @c ARENE_PRECONDITION violation.
304 /// @post The state of the object is as if it had been constructed by @c ptr .
305 /// @note does not participate in overload resolution if @c held_pointer::reset(U) is not well formed.
306 ///
307 template <
308 typename U = held_pointer,
309 constraints<std::enable_if_t<arene::base::pointer::detail::has_reset<held_pointer&, U>>> = nullptr>
310 constexpr void reset(U&& reset_to) noexcept(noexcept(std::declval<held_pointer>().reset(std::declval<U>()))) {
311 ARENE_PRECONDITION(reset_to != nullptr);
312 ptr_.reset(std::forward<U>(reset_to));
313 }
314
315 ///
316 /// @brief Re-assigns the @c non_null to a new held pointer.
317 ///
318 /// The reset is performed by assignment to the held pointer.
319 ///
320 /// @tparam U The type of pointer to rest with. Must be @c assignable to @c held_pointer
321 /// @param reset_to The pointer to reset the @c non_null to.
322 /// @pre @c ptr must not be @c nullptr , or else @c ARENE_PRECONDITION violation.
323 /// @post The state of the object is as if it had been constructed by @c ptr .
324 /// @note does not participate in overload resolution if @c held_pointer::reset(U) is well formed.
325 ///
326 template <
327 typename U = held_pointer,
328 constraints<
329 std::enable_if_t<!arene::base::pointer::detail::has_reset<held_pointer&, U>>,
330 std::enable_if_t<std::is_assignable<held_pointer&, U>::value>> = nullptr>
331 constexpr void reset(U&& reset_to) noexcept(std::is_nothrow_assignable<held_pointer&, U>::value) {
332 ARENE_PRECONDITION(reset_to != nullptr);
333 ptr_ = std::forward<U>(reset_to);
334 }
335
336 /// @brief Resetting to a @c nullptr literal is not supported.
337 constexpr void reset(std::nullptr_t) noexcept = delete;
338
339 ///
340 /// @brief Swaps this with another @c non_null .
341 ///
342 /// @tparam U Must satisfy @c arene::base::is_swappable_v
343 /// @param swap_with The @c non_null to swap with.
344 /// @post @c this is equal to the original @c swap_with, and @c swap_with is equal to the original @c this .
345 ///
346 template <typename U = P, constraints<std::enable_if_t<is_swappable_v<P>>> = nullptr>
347 constexpr void swap(non_null& swap_with) noexcept(is_nothrow_swappable_v<P>) {
348 ::arene::base::swap(ptr_, swap_with.ptr_);
349 }
350
351 // parasoft-begin-suppress AUTOSAR-A11_3_1-a-2 "Hidden friends permitted by A11-3-1 Permit #2"
352 // parasoft-begin-suppress AUTOSAR-M3_3_2-a "False positive: static cannot be applied, not a member function"
353 /// @brief Swaps two @c non_null .
354 ///
355 /// @tparam U Must satisfy @c arene::base::is_swappable_v
356 /// @param lhs The left-hand @c non_null to swap.
357 /// @param rhs The right-hand @c non_null to swap.
358 /// @post Equivalent to calling @c lhs.swap(rhs)
359 /// @see arene::base::non_null::swap
360 ///
361 template <typename U = P, constraints<std::enable_if_t<is_swappable_v<P>>> = nullptr>
362 friend constexpr void swap(non_null& lhs, non_null& rhs) noexcept(noexcept(lhs.swap(rhs))) {
363 lhs.swap(rhs);
364 }
365 // parasoft-end-suppress AUTOSAR-M3_3_2-a
366 // parasoft-end-suppress AUTOSAR-A11_3_1-a-2
367
368 ///
369 /// @brief Arrow operator
370 ///
371 /// @return pointer A pointer to the pointed-to element
372 /// @invariant The returned pointer will never be equal to @c nullptr .
373 /// @note Only exists if @c held_pointer is not @c void* .
374 ///
375 template <typename U = element_type, typename = std::enable_if_t<!std::is_same<std::remove_cv_t<U>, void>::value>>
376 ARENE_NODISCARD constexpr auto operator->() const noexcept -> pointer {
377 return get();
378 }
379
380 ///
381 /// @brief Dereference operator
382 ///
383 /// @return element_type& A reference to the pointed-to element.
384 /// @invariant The returned pointer will never be equal to @c nullptr .
385 /// @note Only exists if @c held_pointer is not @c void* .
386 ///
387 template <typename U = element_type, typename = std::enable_if_t<!std::is_same<std::remove_cv_t<U>, void>::value>>
388 ARENE_NODISCARD constexpr auto operator*() const noexcept -> decltype(auto) {
389 return *get();
390 }
391
392 // parasoft-begin-suppress AUTOSAR-A2_7_3-a-2 "False positive: All overloads are fully are documented"
393 ///
394 /// @brief Conversion to @c bool , equivalent to a @c != comparison to @c nullptr.
395 ///
396 /// @return true @c non_null can never contain @c nullptr , so the return is always @c true .
397 ///
398 /// @{
399 template <typename U = held_pointer, constraints<std::enable_if_t<!std::is_pointer<U>::value>> = nullptr>
400 ARENE_NODISCARD explicit constexpr operator bool() const noexcept {
401 return ptr_ != nullptr;
402 }
403 template <typename U = held_pointer, constraints<std::enable_if_t<std::is_pointer<U>::value>> = nullptr>
404 ARENE_NODISCARD explicit constexpr operator bool() const noexcept {
405 return true;
406 }
407 /// @}
408 // parasoft-end-suppress AUTOSAR-A2_7_3-a-2
409
410 ///
411 /// @brief Boolean negation operator, equivalent to a @c == comparison to @c nullptr.
412 ///
413 /// @return false @c non_null can never contain @c nullptr , so the return is always @c false .
414 ///
415 ARENE_NODISCARD constexpr auto operator!() const noexcept -> bool { return !(static_cast<bool>(*this)); }
416
417 // parasoft-begin-suppress AUTOSAR-A13_5_2-a-2 "Implicit conversion to the underlying pointer type is part of the API"
418 // parasoft-begin-suppress AUTOSAR-A2_7_3-a-2 "False positive: All overloads are fully are documented"
419 // parasoft-begin-suppress AUTOSAR-A13_2_3-a-2 "False positive: This is not a relational operator"
420 // parasoft-begin-suppress AUTOSAR-M9_3_1-a "False positive: This class is a container of the value"
421 // parasoft-begin-suppress AUTOSAR-A9_3_1-a "False positive: This class is a container of the value"
422 ///
423 /// @brief Implicit conversion operator to the underlying pointer
424 ///
425 /// @return The underlying pointer. If @c held_pointer is a raw pointer or sufficiently trivial type, this will be a
426 /// by-value return. Otherwise, it will be a reference.
427 /// @{
428 // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
429 ARENE_NODISCARD constexpr operator held_pointer const&() const& noexcept { return ptr_; }
430 // parasoft-end-suppress AUTOSAR-A13_2_3-a-2
431
432 // parasoft-begin-suppress AUTOSAR-A13_2_3-a "False positive: Not a relational operator"
433 template <typename U = held_pointer, constraints<std::enable_if_t<!std::is_pointer<U>::value>> = nullptr>
434 // NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
435 ARENE_NODISCARD constexpr operator held_pointer&&() && noexcept {
436 return std::move(ptr_);
437 }
438 /// @}
439 // parasoft-end-suppress AUTOSAR-A9_3_1-a
440 // parasoft-end-suppress AUTOSAR-M9_3_1-a
441 // parasoft-end-suppress AUTOSAR-A13_2_3-a
442 // parasoft-end-suppress AUTOSAR-A2_7_3-a-2
443 // parasoft-end-suppress AUTOSAR-A13_5_2-a-2
444
445 // parasoft-begin-suppress AUTOSAR-A2_7_3-a-2 "False positive: All overloads are fully are documented"
446 ///
447 /// @brief Explicit conversion operator to @c U
448 ///
449 /// @tparam U The type to convert the @c non_null to. @c held_pointer must be @c convertible to @c U .
450 /// @return U An instance of the converted-to type produced by applying @c static_cast<U>() to the held pointer.
451 /// @{
452 template <
453 typename U,
454 constraints<
455 std::enable_if_t<!is_non_null_v<U>>,
456 std::enable_if_t<std::is_constructible<U, held_pointer const&>::value>> = nullptr>
457 ARENE_NODISCARD explicit constexpr operator U(
458 ) const& noexcept(std::is_nothrow_constructible<U, held_pointer const&>::value) {
459 return static_cast<U>(ptr_);
460 }
461
462 // parasoft-begin-suppress AUTOSAR-A13_2_3-a "False positive: Not a relational operator"
463 template <
464 typename U,
465 constraints<
466 std::enable_if_t<!is_non_null_v<U>>,
467 std::enable_if_t<!std::is_pointer<U>::value>,
468 std::enable_if_t<std::is_constructible<U, held_pointer&&>::value>> = nullptr>
469 ARENE_NODISCARD explicit constexpr operator U() && noexcept(std::is_nothrow_constructible<U, held_pointer&&>::value) {
470 return static_cast<U>(std::move(ptr_));
471 }
472 /// @}
473 // parasoft-end-suppress AUTOSAR-A13_2_3-a
474 // parasoft-end-suppress AUTOSAR-A2_7_3-a-2
475
476 // parasoft-begin-suppress AUTOSAR-M3_3_2-a "False positive: static cannot be applied, not a member function"
477 // parasoft-begin-suppress AUTOSAR-A13_5_5-b "Mixed comparisons permitted by A13-5-5 Permit #1"
478 // parasoft-begin-suppress AUTOSAR-A11_3_1-a "False positive: A11-3-1 allows friend for comparisons"
479 /// @brief Equality comparison between two @c non_null instances. The result is equivalent to comparing the held
480 /// pointers
481 /// @tparam OtherType The type held in the other @c non_null instance being compared to. @c held_pointer must be @c
482 /// comparable to @c OtherType .
483 /// @param lhs The first value being compared
484 /// @param rhs The second value being compared
485 /// @return The result of the comparison of the held pointer of @c lhs to the held pointer of @c rhs
486 template <
487 typename OtherType,
488 constraints<std::enable_if_t<is_equality_comparable_v<held_pointer const&, OtherType const&>>> = nullptr>
489 ARENE_NODISCARD friend constexpr auto operator==(non_null const& lhs, non_null<OtherType> const& rhs) noexcept
490 -> bool {
491 return lhs.unwrap() == rhs.unwrap();
492 }
493 // parasoft-end-suppress AUTOSAR-A11_3_1-a
494 // parasoft-end-suppress AUTOSAR-A13_5_5-b
495 // parasoft-end-suppress AUTOSAR-M3_3_2-a
496
497 // parasoft-begin-suppress AUTOSAR-A13_5_5-b "Mixed comparisons permitted by A13-5-5 Permit #1"
498 // parasoft-begin-suppress AUTOSAR-A11_3_1-a "False positive: A11-3-1 allows friend for comparisons"
499 /// @brief Equality comparison of @c non_null against another value. The result is equivalent to comparing the held
500 /// pointer against that other value
501 /// @tparam NonNullType Must be @c non_null This is a constrained template parameter to avoid implicit conversions and
502 /// ambiguous overload resolution.
503 /// @tparam OtherType The type to compare the @c non_null to. It must not be a instantiation of @c non_null. @c
504 /// held_pointer must be @c comparable to @c OtherType .
505 /// @param lhs The first value being compared
506 /// @param rhs The second value being compared
507 /// @return The result of the comparison of the held pointer of @c lhs to the other value
508 template <
509 typename NonNullType,
510 typename OtherType,
511 constraints<
512 std::enable_if_t<std::is_same<NonNullType, non_null>::value>,
513 std::enable_if_t<!is_non_null_v<OtherType>>,
514 std::enable_if_t<is_equality_comparable_v<held_pointer const&, OtherType const&>>> = nullptr>
515 ARENE_NODISCARD friend constexpr auto operator==(NonNullType const& lhs, OtherType const& rhs) noexcept -> bool {
516 return lhs.unwrap() == rhs;
517 }
518 // parasoft-end-suppress AUTOSAR-A11_3_1-a
519 // parasoft-end-suppress AUTOSAR-A13_5_5-b
520
521 // parasoft-begin-suppress AUTOSAR-A13_5_5-b "Mixed comparisons permitted by A13-5-5 Permit #1"
522 // parasoft-begin-suppress AUTOSAR-A11_3_1-a "False positive: A11-3-1 allows friend for comparisons"
523 // parasoft-begin-suppress AUTOSAR-A0_1_3-a "This is an inline function used in multiple translation units"
524 /// @brief Equality comparison of @c non_null against a null pointer.
525 /// @param lhs The first value being compared
526 /// @param rhs The second value being compared
527 /// @return The result of this check is always @c false unless the @c non_null instance has been moved from, and wraps
528 /// a movable smart pointer like @c std::unique_ptr
529 ARENE_NODISCARD friend constexpr auto operator==(non_null const& lhs, std::nullptr_t const rhs) noexcept -> bool {
530 std::ignore = rhs;
531 return !lhs;
532 }
533 // parasoft-end-suppress AUTOSAR-A0_1_3-a
534 // parasoft-end-suppress AUTOSAR-A11_3_1-a
535 // parasoft-end-suppress AUTOSAR-A13_5_5-b
536
537 /// @brief Three-way comparison between two @c non_null instances. The result is equivalent to comparing the held
538 /// pointers
539 /// @tparam OtherType The type held in the other @c non_null instance being compared to. @c held_pointer must be @c
540 /// three-way-comparable to @c OtherType .
541 /// @param lhs The first value being compared
542 /// @param rhs The second value being compared
543 /// @return The result of the three-way comparison of the held pointer of @c lhs to the held pointer of @c rhs
544 template <
545 typename OtherType,
546 constraints<std::enable_if_t<compare_three_way_supported_v<held_pointer const&, OtherType const&>>> = nullptr>
547 ARENE_NODISCARD static constexpr auto three_way_compare(non_null const& lhs, non_null<OtherType> const& rhs) noexcept
548 -> strong_ordering {
549 return compare_three_way{}(lhs.unwrap(), rhs.unwrap());
550 }
551
552 /// @brief Three-way comparison of @c non_null against another value. The result is equivalent to comparing the held
553 /// pointer against that other value
554 /// @tparam OtherType The type to compare the @c non_null to. It must not be a instantiation of @c non_null. @c
555 /// held_pointer must be @c comparable to @c OtherType .
556 /// @param lhs The first value being compared
557 /// @param rhs The second value being compared
558 /// @return The result of the three-way comparison of the held pointer of @c lhs to @c rhs
559 template <
560 typename OtherType,
561 constraints<
562 std::enable_if_t<compare_three_way_supported_v<held_pointer const&, OtherType const&>>,
563 std::enable_if_t<!is_non_null_v<OtherType>>> = nullptr>
564 ARENE_NODISCARD static constexpr auto three_way_compare(non_null const& lhs, OtherType const& rhs) noexcept
565 -> strong_ordering {
566 return compare_three_way{}(lhs.unwrap(), rhs);
567 }
568
569 /// @brief Three-way comparison of @c non_null against a null pointer.
570 /// @tparam Dummy Dummy template parameter that is the same as @c held_pointer to enable SFINAE
571 /// @param lhs The @c non_null value being compared
572 /// @return The result of this check is always @c strong_ordering::greater unless the @c non_null instance has been
573 /// moved from, and wraps a movable smart pointer like @c std::unique_ptr
574 template <typename Dummy = held_pointer, constraints<std::enable_if_t<!std::is_pointer<Dummy>::value>> = nullptr>
575 ARENE_NODISCARD static constexpr auto three_way_compare(non_null const& lhs, std::nullptr_t const) noexcept
576 -> strong_ordering {
577 if (!lhs) {
578 return strong_ordering::equal;
579 }
580 return strong_ordering::greater;
581 }
582
583 /// @brief Three-way comparison of @c non_null against a null pointer.
584 /// @tparam Dummy Dummy template parameter that is the same as @c held_pointer to enable SFINAE
585 /// @return The result of this check is always @c strong_ordering::greater
586 template <typename Dummy = held_pointer, constraints<std::enable_if_t<std::is_pointer<Dummy>::value>> = nullptr>
587 ARENE_NODISCARD static constexpr auto three_way_compare(non_null const&, std::nullptr_t const) noexcept
588 -> strong_ordering {
589 return strong_ordering::greater;
590 }
591
592 // parasoft-begin-suppress AUTOSAR-A2_7_3-a-2 "False positive: All overloads are fully are documented"
593 /// @brief Pointer arithmetic is explicitly deleted
594 /// @{
595 template <typename I>
596 constexpr auto operator[](I) = delete;
597 template <typename I>
598 constexpr auto operator[](I) const = delete;
599 template <typename I>
600 constexpr auto operator+(I const&) const -> non_null = delete;
601 template <typename I>
602 constexpr auto operator-(I const&) const -> non_null = delete;
603 constexpr auto operator++() -> non_null& = delete;
604 // parasoft-begin-suppress AUTOSAR-A3_9_1-b-2 "False positive: postincrement requires an int parameter"
605 constexpr auto operator++(int) -> non_null& = delete;
606 // parasoft-end-suppress AUTOSAR-A3_9_1-b-2
607 constexpr auto operator--() -> non_null& = delete;
608 // parasoft-begin-suppress AUTOSAR-A3_9_1-b-2 "False positive: postdecrement requires an int parameter"
609 constexpr auto operator--(int) -> non_null& = delete;
610 // parasoft-end-suppress AUTOSAR-A3_9_1-b-2
611 /// @}
612 // parasoft-end-suppress AUTOSAR-A2_7_3-a-2
613
614 private:
615 /// @brief The held pointer which must not be null
616 held_pointer ptr_;
617};
618// parasoft-end-suppress AUTOSAR-A12_1_2-a-2
619
620///
621/// @brief Factory function to deduce the type of a @c non_null
622///
623/// @tparam P The type of the pointer
624/// @param ptr The pointer to construct the @c non_null from
625/// @return non_null<P> The resulting non-null produced from the input pointer
626template <typename P>
627ARENE_NODISCARD constexpr auto make_non_null(P&& ptr) noexcept -> non_null<std::decay_t<P>> {
628 return non_null<std::decay_t<P>>(std::forward<P>(ptr));
629}
630/// @brief Deleted overload for not constructing a non-null pointer from a null pointer
631/// @param ptr The null pointer
632constexpr void make_non_null(std::nullptr_t ptr) = delete;
633
634///
635/// @brief Alias for a @c non_null which holds a raw pointer
636///
637/// @tparam T The type of the pointed to element
638///
639template <typename T>
640using non_null_ptr = non_null<T*>;
641
642} // namespace base
643} // namespace arene
644
645// parasoft-begin-suppress AUTOSAR-A17_6_1-a-2 "False positive: specialization of standard templates is permitted"
646// parasoft-begin-suppress CERT_CPP-DCL58-a-2 "False positive: specialization of standard templates is permitted"
647namespace std {
648// parasoft-begin-suppress AUTOSAR-A11_0_2-a-2 "False positive: must follow the primary template"
649///
650/// @brief @c std::hash specialization for @c non_null.
651///
652/// The hash is equivalent to the hash of the held pointer.
653/// @tparam P the type of the underlying pointer
654///
655template <typename P>
656struct hash<::arene::base::non_null<P>> {
657 /// @brief Hash the pointer
658 /// @param ptr The pointer to hash
659 /// @return The hashed value
660 constexpr auto operator()(::arene::base::non_null<P> const& ptr) const noexcept -> size_t {
661 return hash<typename ::arene::base::non_null<P>::held_pointer>{}(ptr);
662 }
663};
664// parasoft-end-suppress AUTOSAR-A11_0_2-a-2
665
666} // namespace std
667// parasoft-end-suppress CERT_CPP-DCL58-a-2
668// parasoft-end-suppress AUTOSAR-A17_6_1-a-2
669
670#endif // INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_POINTER_NON_NULL_HPP_
constexpr auto operator--() -> non_null &=delete
Pointer arithmetic is explicitly deleted.
constexpr auto operator[](I) const =delete
Pointer arithmetic is explicitly deleted.
constexpr auto operator=(non_null const &) -> non_null &=default
Default copy assignment.
constexpr auto operator-(I const &) const -> non_null=delete
Pointer arithmetic is explicitly deleted.
constexpr non_null(non_null const &)=default
Default copy constructor.
constexpr auto operator+(I const &) const -> non_null=delete
Pointer arithmetic is explicitly deleted.
~non_null()=default
Default destructor.
constexpr auto operator++() -> non_null &=delete
Pointer arithmetic is explicitly deleted.
constexpr auto operator--(int) -> non_null &=delete
Pointer arithmetic is explicitly deleted.
constexpr auto operator=(non_null &&) -> non_null &=default
Default move assignment.
constexpr non_null(non_null &&)=default
Default move constructor.
constexpr non_null()=delete
non_null cannot be default constructed
constexpr auto operator++(int) -> non_null &=delete
Pointer arithmetic is explicitly deleted.
Definition array_exceptions_disabled.cpp:11
constexpr bool is_non_null_v
Trait that deduces if a type is an non_null to any type.
Definition non_null.hpp:59
Copyright 2026, Toyota Motor Corporation.
Definition array_exceptions_disabled.cpp:10
constexpr auto operator()(::arene::base::non_null< P > const &ptr) const noexcept -> size_t
Hash the pointer.
Definition non_null.hpp:660
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