xref: /xnu-11215.81.4/iokit/DriverKit/bounded_ptr.h (revision d4514f0bc1d3f944c22d92e68b646ac3fb40d452)
1*d4514f0bSApple OSS Distributions //
2*d4514f0bSApple OSS Distributions // Copyright (c) 2019 Apple, Inc. All rights reserved.
3*d4514f0bSApple OSS Distributions //
4*d4514f0bSApple OSS Distributions // @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*d4514f0bSApple OSS Distributions //
6*d4514f0bSApple OSS Distributions // This file contains Original Code and/or Modifications of Original Code
7*d4514f0bSApple OSS Distributions // as defined in and that are subject to the Apple Public Source License
8*d4514f0bSApple OSS Distributions // Version 2.0 (the 'License'). You may not use this file except in
9*d4514f0bSApple OSS Distributions // compliance with the License. The rights granted to you under the License
10*d4514f0bSApple OSS Distributions // may not be used to create, or enable the creation or redistribution of,
11*d4514f0bSApple OSS Distributions // unlawful or unlicensed copies of an Apple operating system, or to
12*d4514f0bSApple OSS Distributions // circumvent, violate, or enable the circumvention or violation of, any
13*d4514f0bSApple OSS Distributions // terms of an Apple operating system software license agreement.
14*d4514f0bSApple OSS Distributions //
15*d4514f0bSApple OSS Distributions // Please obtain a copy of the License at
16*d4514f0bSApple OSS Distributions // http://www.opensource.apple.com/apsl/ and read it before using this file.
17*d4514f0bSApple OSS Distributions //
18*d4514f0bSApple OSS Distributions // The Original Code and all software distributed under the License are
19*d4514f0bSApple OSS Distributions // distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*d4514f0bSApple OSS Distributions // EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*d4514f0bSApple OSS Distributions // INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*d4514f0bSApple OSS Distributions // FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*d4514f0bSApple OSS Distributions // Please see the License for the specific language governing rights and
24*d4514f0bSApple OSS Distributions // limitations under the License.
25*d4514f0bSApple OSS Distributions //
26*d4514f0bSApple OSS Distributions // @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*d4514f0bSApple OSS Distributions //
28*d4514f0bSApple OSS Distributions 
29*d4514f0bSApple OSS Distributions #ifndef XNU_LIBKERN_LIBKERN_CXX_BOUNDED_PTR_H
30*d4514f0bSApple OSS Distributions #define XNU_LIBKERN_LIBKERN_CXX_BOUNDED_PTR_H
31*d4514f0bSApple OSS Distributions 
32*d4514f0bSApple OSS Distributions #if !TAPI
33*d4514f0bSApple OSS Distributions 
34*d4514f0bSApple OSS Distributions #include <stddef.h>
35*d4514f0bSApple OSS Distributions #include <stdint.h>
36*d4514f0bSApple OSS Distributions #include <os/overflow.h>
37*d4514f0bSApple OSS Distributions #include <os/base.h>
38*d4514f0bSApple OSS Distributions 
39*d4514f0bSApple OSS Distributions #if !defined(__improbable)
40*d4514f0bSApple OSS Distributions #   define __improbable(...) __builtin_expect((__VA_ARGS__), 0)
41*d4514f0bSApple OSS Distributions #endif
42*d4514f0bSApple OSS Distributions 
43*d4514f0bSApple OSS Distributions namespace libkern {
44*d4514f0bSApple OSS Distributions namespace detail {
45*d4514f0bSApple OSS Distributions // Reimplementation of things in <type_traits> because we don't seem
46*d4514f0bSApple OSS Distributions // to have the right to rely on the C++ Standard Library (based on
47*d4514f0bSApple OSS Distributions // attempts to compile IOHIDFamily).
48*d4514f0bSApple OSS Distributions // TODO: Do we really need to re-implement this here?
49*d4514f0bSApple OSS Distributions template <typename ...> using void_t = void;
50*d4514f0bSApple OSS Distributions template <typename T> T && declval() noexcept;
51*d4514f0bSApple OSS Distributions using nullptr_t = decltype(nullptr);
52*d4514f0bSApple OSS Distributions template <bool Cond, typename T = void> struct enable_if;
53*d4514f0bSApple OSS Distributions template <typename T> struct enable_if<true, T> { using type = T; };
54*d4514f0bSApple OSS Distributions template <bool Cond, typename T = void> using enable_if_t = typename enable_if<Cond, T>::type;
55*d4514f0bSApple OSS Distributions template <typename T1, typename T2>
56*d4514f0bSApple OSS Distributions constexpr bool is_convertible_v = __is_convertible_to(T1, T2);
57*d4514f0bSApple OSS Distributions 
58*d4514f0bSApple OSS Distributions template <typename T> inline constexpr bool is_void_v = false;
59*d4514f0bSApple OSS Distributions template <> inline constexpr bool is_void_v<void> = true;
60*d4514f0bSApple OSS Distributions template <> inline constexpr bool is_void_v<void const> = true;
61*d4514f0bSApple OSS Distributions 
62*d4514f0bSApple OSS Distributions template <typename T, typename U> struct copy_const { using type = U; };
63*d4514f0bSApple OSS Distributions template <typename T, typename U> struct copy_const<T const, U> { using type = U const; };
64*d4514f0bSApple OSS Distributions template <typename T, typename U> using copy_const_t = typename copy_const<T, U>::type;
65*d4514f0bSApple OSS Distributions 
66*d4514f0bSApple OSS Distributions template <typename T, typename U> struct copy_cv { using type = U; };
67*d4514f0bSApple OSS Distributions template <typename T, typename U> struct copy_cv<T const, U> { using type = U const; };
68*d4514f0bSApple OSS Distributions template <typename T, typename U> struct copy_cv<T volatile, U> { using type = U volatile; };
69*d4514f0bSApple OSS Distributions template <typename T, typename U> struct copy_cv<T const volatile, U> { using type = U const volatile; };
70*d4514f0bSApple OSS Distributions template <typename T, typename U> using copy_cv_t = typename copy_cv<T, U>::type;
71*d4514f0bSApple OSS Distributions 
72*d4514f0bSApple OSS Distributions template <typename T, typename U>
73*d4514f0bSApple OSS Distributions using WhenComparable = void_t<
74*d4514f0bSApple OSS Distributions 	decltype(declval<T>() == declval<U>()),
75*d4514f0bSApple OSS Distributions 	decltype(declval<T>() != declval<U>())
76*d4514f0bSApple OSS Distributions 	>;
77*d4514f0bSApple OSS Distributions 
78*d4514f0bSApple OSS Distributions template <typename T, typename U>
79*d4514f0bSApple OSS Distributions using WhenOrderable = void_t <
80*d4514f0bSApple OSS Distributions     decltype(declval<T>() < declval<U>()),
81*d4514f0bSApple OSS Distributions decltype(declval<T>() > declval<U>()),
82*d4514f0bSApple OSS Distributions decltype(declval<T>() >= declval<U>()),
83*d4514f0bSApple OSS Distributions decltype(declval<T>() <= declval<U>())
84*d4514f0bSApple OSS Distributions >;
85*d4514f0bSApple OSS Distributions 
86*d4514f0bSApple OSS Distributions // Pretend that sizeof(void) is 1, otherwise the in-bounds check doesn't
87*d4514f0bSApple OSS Distributions // make sense for `bounded_ptr<void>`.
88*d4514f0bSApple OSS Distributions template <typename T> constexpr size_t sizeof_v = sizeof(T);
89*d4514f0bSApple OSS Distributions template <>           inline constexpr size_t sizeof_v<void> = 1;
90*d4514f0bSApple OSS Distributions template <>           inline constexpr size_t sizeof_v<void const> = 1;
91*d4514f0bSApple OSS Distributions template <>           inline constexpr size_t sizeof_v<void volatile> = 1;
92*d4514f0bSApple OSS Distributions template <>           inline constexpr size_t sizeof_v<void const volatile> = 1;
93*d4514f0bSApple OSS Distributions } // end namespace detail
94*d4514f0bSApple OSS Distributions 
95*d4514f0bSApple OSS Distributions // Non-owning pointer to an object (or a range of objects) of type `T`
96*d4514f0bSApple OSS Distributions // that validates that the address is within some specified bounds on
97*d4514f0bSApple OSS Distributions // dereference-like operations.
98*d4514f0bSApple OSS Distributions //
99*d4514f0bSApple OSS Distributions // Conceptually, a `bounded_ptr` points within a range of memory `[begin, end)`.
100*d4514f0bSApple OSS Distributions // If accessing any part of the result of dereferencing the pointer would
101*d4514f0bSApple OSS Distributions // lead to an access outside of the `[begin, end)` range, the pointer is
102*d4514f0bSApple OSS Distributions // said to be out-of-bounds. Due to representational constraints, the range
103*d4514f0bSApple OSS Distributions // of in-bounds memory must be no larger than 4GB.
104*d4514f0bSApple OSS Distributions //
105*d4514f0bSApple OSS Distributions // Dereference-like operations (dereference, subscript, pointer member access)
106*d4514f0bSApple OSS Distributions // validate that the pointer is not out-of-bounds. If an out-of-bounds pointer
107*d4514f0bSApple OSS Distributions // is dereferenced, the `TrappingPolicy` is called as
108*d4514f0bSApple OSS Distributions // `TrappingPolicy::trap(some-message)`, and the operation is said to "trap".
109*d4514f0bSApple OSS Distributions // This terminology is used below to describe the behavior of the `TrappingPolicy`.
110*d4514f0bSApple OSS Distributions //
111*d4514f0bSApple OSS Distributions // Pointer arithmetic is allowed (and the bounds are not validated), so it is
112*d4514f0bSApple OSS Distributions // entirely possible to make a `bounded_ptr` point outside of its range.
113*d4514f0bSApple OSS Distributions // However, overflow checking is performed on arithmetic operations, and
114*d4514f0bSApple OSS Distributions // any operation resulting in an overflow will also "trap".
115*d4514f0bSApple OSS Distributions //
116*d4514f0bSApple OSS Distributions // The behavior of the `TrappingPolicy` can be customized as desired, however
117*d4514f0bSApple OSS Distributions // a trap should never return, causing the current `bounded_ptr` operation to
118*d4514f0bSApple OSS Distributions // be aborted. This is important since the trap could signify an integer
119*d4514f0bSApple OSS Distributions // overflow, a null-pointer dereference or something else that would lead to
120*d4514f0bSApple OSS Distributions // undefined behavior (UB) if `TrappingPolicy::trap` were to return.
121*d4514f0bSApple OSS Distributions //
122*d4514f0bSApple OSS Distributions // Creation of `bounded_ptr`s
123*d4514f0bSApple OSS Distributions // ==========================
124*d4514f0bSApple OSS Distributions // `bounded_ptr` provides a single constructor allowing the bounds of the
125*d4514f0bSApple OSS Distributions // pointer to be specified. When integrating `bounded_ptr` into an existing
126*d4514f0bSApple OSS Distributions // code base, it is recommended to use `bounded_ptr` as an iterator obtained
127*d4514f0bSApple OSS Distributions // from other container-like abstractions, instead of manually using the
128*d4514f0bSApple OSS Distributions // constructor that allows specifying a range. Specifying the range manually
129*d4514f0bSApple OSS Distributions // on construction is error-prone, and `bounded_ptr` can't help reduce
130*d4514f0bSApple OSS Distributions // out-of-bounds accesses if the bounds are specified incorrectly.
131*d4514f0bSApple OSS Distributions //
132*d4514f0bSApple OSS Distributions // Furthermore, it is a design choice to not provide a constructor that uses
133*d4514f0bSApple OSS Distributions // relative offsets from the pointer itself to determine the range, because
134*d4514f0bSApple OSS Distributions // such a constructor is deemed more confusing than helpful. For example, is
135*d4514f0bSApple OSS Distributions // the offset a number of bytes or a number of objects? Is the offset inclusive
136*d4514f0bSApple OSS Distributions // or exclusive? Instead, factory functions should be used to create `bounded_ptr`s.
137*d4514f0bSApple OSS Distributions //
138*d4514f0bSApple OSS Distributions // Remark on const-ness
139*d4514f0bSApple OSS Distributions // ====================
140*d4514f0bSApple OSS Distributions // Like for raw pointers, the const-ness of a `bounded_ptr` has no bearing on
141*d4514f0bSApple OSS Distributions // whether the pointee is const. Hence, it is possible to obtain a non-const
142*d4514f0bSApple OSS Distributions // reference to an object from a const `bounded_ptr`. To encode a
143*d4514f0bSApple OSS Distributions // pointer-to-const, simply create a `bounded_ptr<T const>`.
144*d4514f0bSApple OSS Distributions template <typename T, typename TrappingPolicy>
145*d4514f0bSApple OSS Distributions struct __attribute__((trivial_abi)) bounded_ptr {
146*d4514f0bSApple OSS Distributions private:
147*d4514f0bSApple OSS Distributions 	using CharType = detail::copy_cv_t<T, char>;
148*d4514f0bSApple OSS Distributions 
149*d4514f0bSApple OSS Distributions public:
150*d4514f0bSApple OSS Distributions 	// Creates a null `bounded_ptr`.
151*d4514f0bSApple OSS Distributions 	//
152*d4514f0bSApple OSS Distributions 	// A null `bounded_ptr` does not point to any object and is conceptually
153*d4514f0bSApple OSS Distributions 	// out of bounds, so dereferencing it will trap. "Observing" operations
154*d4514f0bSApple OSS Distributions 	// like comparison and check-for-null, along with assignment, are valid
155*d4514f0bSApple OSS Distributions 	// operations on a null `bounded_ptr`.
156*d4514f0bSApple OSS Distributions 	OS_ALWAYS_INLINE constexpr
157*d4514f0bSApple OSS Distributions 	bounded_ptr(detail::nullptr_t)
158*d4514f0bSApple OSS Distributions 		: base_(nullptr), count_(0), offset_(0)
159*d4514f0bSApple OSS Distributions 	{
160*d4514f0bSApple OSS Distributions 	}
161*d4514f0bSApple OSS Distributions 
162*d4514f0bSApple OSS Distributions 	OS_ALWAYS_INLINE constexpr
163*d4514f0bSApple OSS Distributions 	explicit
164*d4514f0bSApple OSS Distributions 	bounded_ptr()
165*d4514f0bSApple OSS Distributions 		: bounded_ptr(nullptr)
166*d4514f0bSApple OSS Distributions 	{
167*d4514f0bSApple OSS Distributions 	}
168*d4514f0bSApple OSS Distributions 
169*d4514f0bSApple OSS Distributions 	// Creates a `bounded_ptr` pointing to the given object, and whose bounds
170*d4514f0bSApple OSS Distributions 	// are described by the provided `[begin, end)` range.
171*d4514f0bSApple OSS Distributions 	//
172*d4514f0bSApple OSS Distributions 	// This constructor does not check whether the constructed pointer is
173*d4514f0bSApple OSS Distributions 	// within its bounds. However, it does check that the provided `[begin, end)`
174*d4514f0bSApple OSS Distributions 	// range is a valid range (that is, `begin <= end`).
175*d4514f0bSApple OSS Distributions 	//
176*d4514f0bSApple OSS Distributions 	// Furthermore, the number of bytes in the range of in-bounds memory must be
177*d4514f0bSApple OSS Distributions 	// representable by a uint32_t, which means that there can be no more than
178*d4514f0bSApple OSS Distributions 	// 2^32 bytes (i.e. 4GB) in that range. Otherwise, the constructor will trap.
179*d4514f0bSApple OSS Distributions 	OS_ALWAYS_INLINE explicit
180*d4514f0bSApple OSS Distributions 	bounded_ptr(T* pointer, T const* begin, T const* end)
181*d4514f0bSApple OSS Distributions 	{
182*d4514f0bSApple OSS Distributions 		base_ = reinterpret_cast<CharType*>(const_cast<T*>(begin));
183*d4514f0bSApple OSS Distributions 
184*d4514f0bSApple OSS Distributions 		// Store (end - begin) into count_, making sure we don't overflow
185*d4514f0bSApple OSS Distributions 		if (__improbable(os_sub_overflow(reinterpret_cast<uintptr_t>(end),
186*d4514f0bSApple OSS Distributions 		    reinterpret_cast<uintptr_t>(begin),
187*d4514f0bSApple OSS Distributions 		    &count_))) {
188*d4514f0bSApple OSS Distributions 			TrappingPolicy::trap("The range of valid memory is too large to be represented "
189*d4514f0bSApple OSS Distributions 			    "by this type, or [begin, end) is not a well-formed range");
190*d4514f0bSApple OSS Distributions 		}
191*d4514f0bSApple OSS Distributions 
192*d4514f0bSApple OSS Distributions 		// Store (pointer - begin) into offset_, making sure we don't overflow.
193*d4514f0bSApple OSS Distributions 		// Note that offset_ can be negative if `pointer` is outside of the
194*d4514f0bSApple OSS Distributions 		// range delimited by [begin, end), which can be valid if it represents
195*d4514f0bSApple OSS Distributions 		// e.g. a subrange of an array.
196*d4514f0bSApple OSS Distributions 		if (__improbable(os_sub_overflow(reinterpret_cast<uintptr_t>(pointer),
197*d4514f0bSApple OSS Distributions 		    reinterpret_cast<uintptr_t>(begin),
198*d4514f0bSApple OSS Distributions 		    &offset_))) {
199*d4514f0bSApple OSS Distributions 			TrappingPolicy::trap("The offset of the pointer inside its valid memory "
200*d4514f0bSApple OSS Distributions 			    "range can't be represented using int32_t");
201*d4514f0bSApple OSS Distributions 		}
202*d4514f0bSApple OSS Distributions 	}
203*d4514f0bSApple OSS Distributions 
204*d4514f0bSApple OSS Distributions 	// Creates a `bounded_ptr` to a type `T` from a `bounded_ptr` to a type `U`.
205*d4514f0bSApple OSS Distributions 	//
206*d4514f0bSApple OSS Distributions 	// This converting constructor is enabled whenever `U*` is implicitly
207*d4514f0bSApple OSS Distributions 	// convertible to `T*`. This allows the usual implicit conversions
208*d4514f0bSApple OSS Distributions 	// between base-and-derived types, and also from any type `U*` to a
209*d4514f0bSApple OSS Distributions 	// `void*`. If other casts (like between unrelated pointer types) are
210*d4514f0bSApple OSS Distributions 	// desired, `libkern::reinterpret_pointer_cast` can be used instead.
211*d4514f0bSApple OSS Distributions 	//
212*d4514f0bSApple OSS Distributions 	// The bounds on the resulting `bounded_ptr` are inherited from the
213*d4514f0bSApple OSS Distributions 	// original `bounded_ptr`.
214*d4514f0bSApple OSS Distributions 	template <typename U, typename Policy, typename = detail::enable_if_t<detail::is_convertible_v<U*, T*> > >
215*d4514f0bSApple OSS Distributions 	OS_ALWAYS_INLINE
216*d4514f0bSApple OSS Distributions 	bounded_ptr(bounded_ptr<U, Policy> const & other)
217*d4514f0bSApple OSS Distributions 		: base_(other.base_)
218*d4514f0bSApple OSS Distributions 		, count_(other.count_)
219*d4514f0bSApple OSS Distributions 		, offset_(static_cast<int32_t>(reinterpret_cast<CharType*>(static_cast<T*>(other.get_ptr_())) - other.base_))
220*d4514f0bSApple OSS Distributions 	{
221*d4514f0bSApple OSS Distributions 	}
222*d4514f0bSApple OSS Distributions 
223*d4514f0bSApple OSS Distributions 	// Assigns a `bounded_ptr` to a type `U` to a `bounded_ptr` to a type `T`,
224*d4514f0bSApple OSS Distributions 	// as long as `U*` is convertible to `T*`.
225*d4514f0bSApple OSS Distributions 	//
226*d4514f0bSApple OSS Distributions 	// This is a rebinding operation, like assignment between raw pointers,
227*d4514f0bSApple OSS Distributions 	// and the destination `bounded_ptr` will inherit the bounds of the
228*d4514f0bSApple OSS Distributions 	// source `bounded_ptr`.
229*d4514f0bSApple OSS Distributions 	template <typename U, typename Policy, typename = detail::enable_if_t<detail::is_convertible_v<U*, T*> > >
230*d4514f0bSApple OSS Distributions 	OS_ALWAYS_INLINE bounded_ptr&
231*d4514f0bSApple OSS Distributions 	operator=(bounded_ptr<U, Policy> const& other)
232*d4514f0bSApple OSS Distributions 	{
233*d4514f0bSApple OSS Distributions 		base_ = other.base_;
234*d4514f0bSApple OSS Distributions 		count_ = other.count_;
235*d4514f0bSApple OSS Distributions 		offset_ = static_cast<int32_t>(reinterpret_cast<CharType*>(static_cast<T*>(other.get_ptr_())) - other.base_);
236*d4514f0bSApple OSS Distributions 		return *this;
237*d4514f0bSApple OSS Distributions 	}
238*d4514f0bSApple OSS Distributions 
239*d4514f0bSApple OSS Distributions 	// Sets a `bounded_ptr` to null.
240*d4514f0bSApple OSS Distributions 	//
241*d4514f0bSApple OSS Distributions 	// This is effectively equivalent to assigning a default-constructed
242*d4514f0bSApple OSS Distributions 	// `bounded_ptr` to the target. As a result, the original bounds of
243*d4514f0bSApple OSS Distributions 	// the `bounded_ptr` are discarded, and the resulting `bounded_ptr`
244*d4514f0bSApple OSS Distributions 	// is both out-of-bounds and also has no bounds assigned to it (like
245*d4514f0bSApple OSS Distributions 	// a default-constructed `bounded_ptr`).
246*d4514f0bSApple OSS Distributions 	OS_ALWAYS_INLINE bounded_ptr&
247*d4514f0bSApple OSS Distributions 	operator=(detail::nullptr_t)
248*d4514f0bSApple OSS Distributions 	{
249*d4514f0bSApple OSS Distributions 		*this = bounded_ptr();
250*d4514f0bSApple OSS Distributions 		return *this;
251*d4514f0bSApple OSS Distributions 	}
252*d4514f0bSApple OSS Distributions 
253*d4514f0bSApple OSS Distributions 	// Returns a reference to the object pointed-to by the `bounded_ptr`.
254*d4514f0bSApple OSS Distributions 	//
255*d4514f0bSApple OSS Distributions 	// Traps if the pointer is pointing outside of its bounds.
256*d4514f0bSApple OSS Distributions 	//
257*d4514f0bSApple OSS Distributions 	// Also note that this function will trap when dereferencing a null
258*d4514f0bSApple OSS Distributions 	// `bounded_ptr`, unless the bounds of the pointer have been set and
259*d4514f0bSApple OSS Distributions 	// include address 0, in which case there's effectively nothing to
260*d4514f0bSApple OSS Distributions 	// diagnose.
261*d4514f0bSApple OSS Distributions 	template <typename T_ = T> // delay instantiation to avoid forming invalid ref for bounded_ptr<void>
262*d4514f0bSApple OSS Distributions 	OS_ALWAYS_INLINE T_&
263*d4514f0bSApple OSS Distributions 	operator*() const
264*d4514f0bSApple OSS Distributions 	{
265*d4514f0bSApple OSS Distributions 		if (__improbable(!in_bounds_())) {
266*d4514f0bSApple OSS Distributions 			TrappingPolicy::trap("bounded_ptr<T>::operator*: Dereferencing this pointer "
267*d4514f0bSApple OSS Distributions 			    "would access memory outside of the bounds set originally");
268*d4514f0bSApple OSS Distributions 		}
269*d4514f0bSApple OSS Distributions 		return *get_ptr_();
270*d4514f0bSApple OSS Distributions 	}
271*d4514f0bSApple OSS Distributions 
272*d4514f0bSApple OSS Distributions 	OS_ALWAYS_INLINE T*
273*d4514f0bSApple OSS Distributions 	operator->() const
274*d4514f0bSApple OSS Distributions 	{
275*d4514f0bSApple OSS Distributions 		if (__improbable(!in_bounds_())) {
276*d4514f0bSApple OSS Distributions 			TrappingPolicy::trap("bounded_ptr<T>::operator->: Accessing a member through this pointer "
277*d4514f0bSApple OSS Distributions 			    "would access memory outside of the bounds set originally");
278*d4514f0bSApple OSS Distributions 		}
279*d4514f0bSApple OSS Distributions 		return get_ptr_();
280*d4514f0bSApple OSS Distributions 	}
281*d4514f0bSApple OSS Distributions 
282*d4514f0bSApple OSS Distributions 	// Provides access to the n-th element past the given pointer.
283*d4514f0bSApple OSS Distributions 	//
284*d4514f0bSApple OSS Distributions 	// The `bounded_ptr` validates whether the provided index is within the
285*d4514f0bSApple OSS Distributions 	// bounds of the `bounded_ptr`. Like for raw pointers, a negative index
286*d4514f0bSApple OSS Distributions 	// may be passed, in which case the pointer is accessed at a negative
287*d4514f0bSApple OSS Distributions 	// offset (which must still be in bounds).
288*d4514f0bSApple OSS Distributions 	template <typename T_ = T> // delay instantiation to avoid forming invalid ref for bounded_ptr<void>
289*d4514f0bSApple OSS Distributions 	OS_ALWAYS_INLINE T_&
290*d4514f0bSApple OSS Distributions 	operator[](ptrdiff_t n) const
291*d4514f0bSApple OSS Distributions 	{
292*d4514f0bSApple OSS Distributions 		return *(*this + n);
293*d4514f0bSApple OSS Distributions 	}
294*d4514f0bSApple OSS Distributions 
295*d4514f0bSApple OSS Distributions 	// Converts a `bounded_ptr` to a raw pointer, after checking it is within
296*d4514f0bSApple OSS Distributions 	// its bounds.
297*d4514f0bSApple OSS Distributions 	//
298*d4514f0bSApple OSS Distributions 	// The primary intended usage of this function is to aid bridging between
299*d4514f0bSApple OSS Distributions 	// code that uses `bounded_ptr`s and code that does not.
300*d4514f0bSApple OSS Distributions 	OS_ALWAYS_INLINE T*
301*d4514f0bSApple OSS Distributions 	discard_bounds() const
302*d4514f0bSApple OSS Distributions 	{
303*d4514f0bSApple OSS Distributions 		if (__improbable(!in_bounds_())) {
304*d4514f0bSApple OSS Distributions 			TrappingPolicy::trap("bounded_ptr<T>::discard_bounds: Discarding the bounds on "
305*d4514f0bSApple OSS Distributions 			    "this pointer would lose the fact that it is outside of the "
306*d4514f0bSApple OSS Distributions 			    "bounds set originally");
307*d4514f0bSApple OSS Distributions 		}
308*d4514f0bSApple OSS Distributions 		return get_ptr_();
309*d4514f0bSApple OSS Distributions 	}
310*d4514f0bSApple OSS Distributions 
311*d4514f0bSApple OSS Distributions 	// Converts a `bounded_ptr` to a raw pointer, without checking whether the
312*d4514f0bSApple OSS Distributions 	// pointer is within its bounds.
313*d4514f0bSApple OSS Distributions 	//
314*d4514f0bSApple OSS Distributions 	// Like `discard_bounds()`, the primary intended usage of this function
315*d4514f0bSApple OSS Distributions 	// is to aid bridging between code that uses `bounded_ptr`s and code that
316*d4514f0bSApple OSS Distributions 	// does not. However, unlike `discard_bounds()`, this function does not
317*d4514f0bSApple OSS Distributions 	// validate that the returned pointer is in bounds. This functionality is
318*d4514f0bSApple OSS Distributions 	// necessary when the pointer represents something that can't be
319*d4514f0bSApple OSS Distributions 	// dereferenced (hence it's OK for it to be out-of-bounds), but that
320*d4514f0bSApple OSS Distributions 	// is still useful for other purposes like comparing against other
321*d4514f0bSApple OSS Distributions 	// pointers. An example of that is the `end` pointer in a half-open
322*d4514f0bSApple OSS Distributions 	// interval `[begin, end)`, where the `end` pointer is out-of-bounds and
323*d4514f0bSApple OSS Distributions 	// can't be dereferenced, yet it's still useful to delimit the range.
324*d4514f0bSApple OSS Distributions 	OS_ALWAYS_INLINE T*
325*d4514f0bSApple OSS Distributions 	unsafe_discard_bounds() const
326*d4514f0bSApple OSS Distributions 	{
327*d4514f0bSApple OSS Distributions 		return get_ptr_();
328*d4514f0bSApple OSS Distributions 	}
329*d4514f0bSApple OSS Distributions 
330*d4514f0bSApple OSS Distributions 	// Implicit conversion to bool, returning whether the pointer is null.
331*d4514f0bSApple OSS Distributions 	//
332*d4514f0bSApple OSS Distributions 	// This operation does not perform any validation of the bounds.
333*d4514f0bSApple OSS Distributions 	OS_ALWAYS_INLINE explicit
334*d4514f0bSApple OSS Distributions 	operator bool() const
335*d4514f0bSApple OSS Distributions 	{
336*d4514f0bSApple OSS Distributions 		return get_ptr_() != nullptr;
337*d4514f0bSApple OSS Distributions 	}
338*d4514f0bSApple OSS Distributions 
339*d4514f0bSApple OSS Distributions 	// Increment/decrement a `bounded_ptr`.
340*d4514f0bSApple OSS Distributions 	//
341*d4514f0bSApple OSS Distributions 	// Like for other arithmetic operations, this does not check whether the
342*d4514f0bSApple OSS Distributions 	// increment or decrement operation results in an out-of-bounds pointer.
343*d4514f0bSApple OSS Distributions 	OS_ALWAYS_INLINE bounded_ptr&
344*d4514f0bSApple OSS Distributions 	operator++()
345*d4514f0bSApple OSS Distributions 	{
346*d4514f0bSApple OSS Distributions 		*this += 1;
347*d4514f0bSApple OSS Distributions 		return *this;
348*d4514f0bSApple OSS Distributions 	}
349*d4514f0bSApple OSS Distributions 	OS_ALWAYS_INLINE bounded_ptr
350*d4514f0bSApple OSS Distributions 	operator++(int)
351*d4514f0bSApple OSS Distributions 	{
352*d4514f0bSApple OSS Distributions 		bounded_ptr old = *this;
353*d4514f0bSApple OSS Distributions 		++*this;
354*d4514f0bSApple OSS Distributions 		return old;
355*d4514f0bSApple OSS Distributions 	}
356*d4514f0bSApple OSS Distributions 	OS_ALWAYS_INLINE bounded_ptr&
357*d4514f0bSApple OSS Distributions 	operator--()
358*d4514f0bSApple OSS Distributions 	{
359*d4514f0bSApple OSS Distributions 		*this -= 1;
360*d4514f0bSApple OSS Distributions 		return *this;
361*d4514f0bSApple OSS Distributions 	}
362*d4514f0bSApple OSS Distributions 	OS_ALWAYS_INLINE bounded_ptr
363*d4514f0bSApple OSS Distributions 	operator--(int)
364*d4514f0bSApple OSS Distributions 	{
365*d4514f0bSApple OSS Distributions 		bounded_ptr old = *this;
366*d4514f0bSApple OSS Distributions 		--*this;
367*d4514f0bSApple OSS Distributions 		return old;
368*d4514f0bSApple OSS Distributions 	}
369*d4514f0bSApple OSS Distributions 
370*d4514f0bSApple OSS Distributions 	// Increment or decrement a `bounded_ptr` by a given offset.
371*d4514f0bSApple OSS Distributions 	//
372*d4514f0bSApple OSS Distributions 	// This is equivalent to adding the given offset to the underlying raw
373*d4514f0bSApple OSS Distributions 	// pointer. In particular, the bounds of the `bounded_ptr` are left
374*d4514f0bSApple OSS Distributions 	// untouched by this operation. Furthermore, like for raw pointers, it
375*d4514f0bSApple OSS Distributions 	// is possible to provide a negative offset, which will have the effect
376*d4514f0bSApple OSS Distributions 	// of decrementing the `bounded_ptr` instead of incrementing it.
377*d4514f0bSApple OSS Distributions 	//
378*d4514f0bSApple OSS Distributions 	// Also note that the offset is NOT a number of bytes -- just like for
379*d4514f0bSApple OSS Distributions 	// raw pointers, it is a number of "positions" to move the pointer from,
380*d4514f0bSApple OSS Distributions 	// which essentially means `n * sizeof(T)` bytes. Again, this works exactly
381*d4514f0bSApple OSS Distributions 	// the same as a raw pointer to an object of type `T`.
382*d4514f0bSApple OSS Distributions 	//
383*d4514f0bSApple OSS Distributions 	// Like other arithmetic operations, this does not check whether the
384*d4514f0bSApple OSS Distributions 	// increment or decrement operation results in an out-of-bounds pointer.
385*d4514f0bSApple OSS Distributions 	// However, this does check whether the arithmetic operation would result
386*d4514f0bSApple OSS Distributions 	// in an overflow, in which case the operation will trap.
387*d4514f0bSApple OSS Distributions 	template <typename T_ = T>
388*d4514f0bSApple OSS Distributions 	OS_ALWAYS_INLINE bounded_ptr&
389*d4514f0bSApple OSS Distributions 	operator+=(ptrdiff_t n)
390*d4514f0bSApple OSS Distributions 	{
391*d4514f0bSApple OSS Distributions 		static_assert(!detail::is_void_v<T_>, "Arithmetic on bounded_ptr<void> is not allowed.");
392*d4514f0bSApple OSS Distributions 
393*d4514f0bSApple OSS Distributions 		ptrdiff_t bytes;
394*d4514f0bSApple OSS Distributions 		if (__improbable(os_mul_overflow(n, sizeof(T), &bytes))) {
395*d4514f0bSApple OSS Distributions 			TrappingPolicy::trap(
396*d4514f0bSApple OSS Distributions 				"bounded_ptr<T>::operator+=(n): Calculating the number of bytes to "
397*d4514f0bSApple OSS Distributions 				"add to the offset (n * sizeof(T)) would trigger an overflow");
398*d4514f0bSApple OSS Distributions 		}
399*d4514f0bSApple OSS Distributions 		if (__improbable(os_add_overflow(offset_, bytes, &offset_))) {
400*d4514f0bSApple OSS Distributions 			TrappingPolicy::trap(
401*d4514f0bSApple OSS Distributions 				"bounded_ptr<T>::operator+=(n): Adding the specified number of bytes "
402*d4514f0bSApple OSS Distributions 				"to the offset representing the current position would overflow.");
403*d4514f0bSApple OSS Distributions 		}
404*d4514f0bSApple OSS Distributions 		return *this;
405*d4514f0bSApple OSS Distributions 	}
406*d4514f0bSApple OSS Distributions 
407*d4514f0bSApple OSS Distributions 	template <typename T_ = T>
408*d4514f0bSApple OSS Distributions 	OS_ALWAYS_INLINE bounded_ptr&
409*d4514f0bSApple OSS Distributions 	operator-=(ptrdiff_t n)
410*d4514f0bSApple OSS Distributions 	{
411*d4514f0bSApple OSS Distributions 		static_assert(!detail::is_void_v<T_>, "Arithmetic on bounded_ptr<void> is not allowed.");
412*d4514f0bSApple OSS Distributions 
413*d4514f0bSApple OSS Distributions 		ptrdiff_t bytes;
414*d4514f0bSApple OSS Distributions 		if (__improbable(os_mul_overflow(n, sizeof(T), &bytes))) {
415*d4514f0bSApple OSS Distributions 			TrappingPolicy::trap(
416*d4514f0bSApple OSS Distributions 				"bounded_ptr<T>::operator-=(n): Calculating the number of bytes to "
417*d4514f0bSApple OSS Distributions 				"subtract from the offset (n * sizeof(T)) would trigger an overflow");
418*d4514f0bSApple OSS Distributions 		}
419*d4514f0bSApple OSS Distributions 		if (__improbable(os_sub_overflow(offset_, bytes, &offset_))) {
420*d4514f0bSApple OSS Distributions 			TrappingPolicy::trap(
421*d4514f0bSApple OSS Distributions 				"bounded_ptr<T>::operator-=(n): Subtracting the specified number of bytes "
422*d4514f0bSApple OSS Distributions 				"from the offset representing the current position would overflow.");
423*d4514f0bSApple OSS Distributions 		}
424*d4514f0bSApple OSS Distributions 		return *this;
425*d4514f0bSApple OSS Distributions 	}
426*d4514f0bSApple OSS Distributions 
427*d4514f0bSApple OSS Distributions 	friend OS_ALWAYS_INLINE bounded_ptr
428*d4514f0bSApple OSS Distributions 	operator+(bounded_ptr p, ptrdiff_t n)
429*d4514f0bSApple OSS Distributions 	{
430*d4514f0bSApple OSS Distributions 		p += n;
431*d4514f0bSApple OSS Distributions 		return p;
432*d4514f0bSApple OSS Distributions 	}
433*d4514f0bSApple OSS Distributions 	friend OS_ALWAYS_INLINE bounded_ptr
434*d4514f0bSApple OSS Distributions 	operator+(ptrdiff_t n, bounded_ptr p)
435*d4514f0bSApple OSS Distributions 	{
436*d4514f0bSApple OSS Distributions 		p += n;
437*d4514f0bSApple OSS Distributions 		return p;
438*d4514f0bSApple OSS Distributions 	}
439*d4514f0bSApple OSS Distributions 	friend OS_ALWAYS_INLINE bounded_ptr
440*d4514f0bSApple OSS Distributions 	operator-(bounded_ptr p, ptrdiff_t n)
441*d4514f0bSApple OSS Distributions 	{
442*d4514f0bSApple OSS Distributions 		p -= n;
443*d4514f0bSApple OSS Distributions 		return p;
444*d4514f0bSApple OSS Distributions 	}
445*d4514f0bSApple OSS Distributions 
446*d4514f0bSApple OSS Distributions 	// Returns the difference between two `bounded_ptr`s.
447*d4514f0bSApple OSS Distributions 	//
448*d4514f0bSApple OSS Distributions 	// This is semantically equivalent to subtracting the two underlying
449*d4514f0bSApple OSS Distributions 	// pointers. The bounds of the pointers are not validated by this
450*d4514f0bSApple OSS Distributions 	// operation.
451*d4514f0bSApple OSS Distributions 	friend OS_ALWAYS_INLINE ptrdiff_t
452*d4514f0bSApple OSS Distributions 	operator-(bounded_ptr const& a, bounded_ptr const& b)
453*d4514f0bSApple OSS Distributions 	{
454*d4514f0bSApple OSS Distributions 		return a.get_ptr_() - b.get_ptr_();
455*d4514f0bSApple OSS Distributions 	}
456*d4514f0bSApple OSS Distributions 
457*d4514f0bSApple OSS Distributions 	friend OS_ALWAYS_INLINE ptrdiff_t
458*d4514f0bSApple OSS Distributions 	operator-(bounded_ptr const& a, T const* b)
459*d4514f0bSApple OSS Distributions 	{
460*d4514f0bSApple OSS Distributions 		return a.get_ptr_() - b;
461*d4514f0bSApple OSS Distributions 	}
462*d4514f0bSApple OSS Distributions 
463*d4514f0bSApple OSS Distributions 	friend OS_ALWAYS_INLINE ptrdiff_t
464*d4514f0bSApple OSS Distributions 	operator-(T const* a, bounded_ptr const& b)
465*d4514f0bSApple OSS Distributions 	{
466*d4514f0bSApple OSS Distributions 		return a - b.get_ptr_();
467*d4514f0bSApple OSS Distributions 	}
468*d4514f0bSApple OSS Distributions 
469*d4514f0bSApple OSS Distributions private:
470*d4514f0bSApple OSS Distributions 	OS_ALWAYS_INLINE bool
471*d4514f0bSApple OSS Distributions 	in_bounds_() const
472*d4514f0bSApple OSS Distributions 	{
473*d4514f0bSApple OSS Distributions 		static_assert(detail::sizeof_v<T> <= UINT32_MAX - INT32_MAX,
474*d4514f0bSApple OSS Distributions 		    "The type pointed-to by bounded_ptr is too large, which would defeat "
475*d4514f0bSApple OSS Distributions 		    "our optimization to check for inboundedness using arithmetic on unsigned");
476*d4514f0bSApple OSS Distributions 		return offset_ >= 0 && static_cast<uint32_t>(offset_) + static_cast<uint32_t>(detail::sizeof_v<T>) <= count_;
477*d4514f0bSApple OSS Distributions 	}
478*d4514f0bSApple OSS Distributions 
479*d4514f0bSApple OSS Distributions 	OS_ALWAYS_INLINE T*
480*d4514f0bSApple OSS Distributions 	get_ptr_() const
481*d4514f0bSApple OSS Distributions 	{
482*d4514f0bSApple OSS Distributions 		// Compute `base_ + offset_`, catching overflows.
483*d4514f0bSApple OSS Distributions 		uintptr_t ptr;
484*d4514f0bSApple OSS Distributions 		if (__improbable(os_add_overflow(reinterpret_cast<uintptr_t>(base_), offset_, &ptr))) {
485*d4514f0bSApple OSS Distributions 			TrappingPolicy::trap("This bounded_ptr is pointing to memory outside of what can "
486*d4514f0bSApple OSS Distributions 			    "be represented by a native pointer.");
487*d4514f0bSApple OSS Distributions 		}
488*d4514f0bSApple OSS Distributions 		return reinterpret_cast<T*>(ptr);
489*d4514f0bSApple OSS Distributions 	}
490*d4514f0bSApple OSS Distributions 
491*d4514f0bSApple OSS Distributions 	template <typename T_, typename U, typename Policy>
492*d4514f0bSApple OSS Distributions 	friend bounded_ptr<T_, Policy> reinterpret_pointer_cast(bounded_ptr<U, Policy> const&) noexcept;
493*d4514f0bSApple OSS Distributions 
494*d4514f0bSApple OSS Distributions 	template <typename U, typename P> friend struct bounded_ptr; // for cross-type operations and conversions
495*d4514f0bSApple OSS Distributions 
496*d4514f0bSApple OSS Distributions 	CharType* base_; // pointer to the beginning of the valid address range
497*d4514f0bSApple OSS Distributions 	uint32_t count_; // number of bytes considered in-bounds (non-negative)
498*d4514f0bSApple OSS Distributions 	int32_t offset_; // current offset into the range, in bytes
499*d4514f0bSApple OSS Distributions };
500*d4514f0bSApple OSS Distributions 
501*d4514f0bSApple OSS Distributions // Returns whether two `bounded_ptr`s point to the same object.
502*d4514f0bSApple OSS Distributions //
503*d4514f0bSApple OSS Distributions // This comparison is semantically equivalent to comparing the underlying
504*d4514f0bSApple OSS Distributions // raw pointers. In particular, it doesn't validate the bounds of either
505*d4514f0bSApple OSS Distributions // `bounded_ptr`, nor does it compare whether the two `bounded_ptr`s have
506*d4514f0bSApple OSS Distributions // the same bounds.
507*d4514f0bSApple OSS Distributions //
508*d4514f0bSApple OSS Distributions // This comparison is enabled between `bounded_ptr`s whenever the two
509*d4514f0bSApple OSS Distributions // corresponding raw pointer types are comparable. Comparison between a
510*d4514f0bSApple OSS Distributions // raw pointer and a `bounded_ptr` is also allowed, so long as the
511*d4514f0bSApple OSS Distributions // two corresponding raw pointer types are comparable.
512*d4514f0bSApple OSS Distributions template <typename T, typename P1, typename U, typename P2, typename = detail::WhenComparable<T*, U*> >
513*d4514f0bSApple OSS Distributions OS_ALWAYS_INLINE bool
514*d4514f0bSApple OSS Distributions operator==(bounded_ptr<T, P1> const& a, bounded_ptr<U, P2> const& b)
515*d4514f0bSApple OSS Distributions {
516*d4514f0bSApple OSS Distributions 	return a.unsafe_discard_bounds() == b.unsafe_discard_bounds();
517*d4514f0bSApple OSS Distributions }
518*d4514f0bSApple OSS Distributions 
519*d4514f0bSApple OSS Distributions template <typename T, typename P1, typename U, typename P2, typename = detail::WhenComparable<T*, U*> >
520*d4514f0bSApple OSS Distributions OS_ALWAYS_INLINE bool
521*d4514f0bSApple OSS Distributions operator!=(bounded_ptr<T, P1> const& a, bounded_ptr<U, P2> const& b)
522*d4514f0bSApple OSS Distributions {
523*d4514f0bSApple OSS Distributions 	return !(a == b);
524*d4514f0bSApple OSS Distributions }
525*d4514f0bSApple OSS Distributions 
526*d4514f0bSApple OSS Distributions template <typename T, typename P, typename U, typename = detail::WhenComparable<T*, U*> >
527*d4514f0bSApple OSS Distributions OS_ALWAYS_INLINE bool
528*d4514f0bSApple OSS Distributions operator==(bounded_ptr<T, P> const& a, U* b)
529*d4514f0bSApple OSS Distributions {
530*d4514f0bSApple OSS Distributions 	return a.unsafe_discard_bounds() == b;
531*d4514f0bSApple OSS Distributions }
532*d4514f0bSApple OSS Distributions 
533*d4514f0bSApple OSS Distributions template <typename T, typename P, typename U, typename = detail::WhenComparable<T*, U*> >
534*d4514f0bSApple OSS Distributions OS_ALWAYS_INLINE bool
535*d4514f0bSApple OSS Distributions operator==(U* a, bounded_ptr<T, P> const& b)
536*d4514f0bSApple OSS Distributions {
537*d4514f0bSApple OSS Distributions 	return a == b.unsafe_discard_bounds();
538*d4514f0bSApple OSS Distributions }
539*d4514f0bSApple OSS Distributions 
540*d4514f0bSApple OSS Distributions template <typename T, typename P, typename U, typename = detail::WhenComparable<T*, U*> >
541*d4514f0bSApple OSS Distributions OS_ALWAYS_INLINE bool
542*d4514f0bSApple OSS Distributions operator!=(bounded_ptr<T, P> const& a, U* b)
543*d4514f0bSApple OSS Distributions {
544*d4514f0bSApple OSS Distributions 	return !(a == b);
545*d4514f0bSApple OSS Distributions }
546*d4514f0bSApple OSS Distributions 
547*d4514f0bSApple OSS Distributions template <typename T, typename P, typename U, typename = detail::WhenComparable<T*, U*> >
548*d4514f0bSApple OSS Distributions OS_ALWAYS_INLINE bool
549*d4514f0bSApple OSS Distributions operator!=(U* a, bounded_ptr<T, P> const& b)
550*d4514f0bSApple OSS Distributions {
551*d4514f0bSApple OSS Distributions 	return !(a == b);
552*d4514f0bSApple OSS Distributions }
553*d4514f0bSApple OSS Distributions 
554*d4514f0bSApple OSS Distributions template <typename T, typename Policy>
555*d4514f0bSApple OSS Distributions OS_ALWAYS_INLINE bool
556*d4514f0bSApple OSS Distributions operator==(detail::nullptr_t, bounded_ptr<T, Policy> const& p)
557*d4514f0bSApple OSS Distributions {
558*d4514f0bSApple OSS Distributions 	return p.unsafe_discard_bounds() == nullptr;
559*d4514f0bSApple OSS Distributions }
560*d4514f0bSApple OSS Distributions 
561*d4514f0bSApple OSS Distributions template <typename T, typename Policy>
562*d4514f0bSApple OSS Distributions OS_ALWAYS_INLINE bool
563*d4514f0bSApple OSS Distributions operator!=(detail::nullptr_t, bounded_ptr<T, Policy> const& p)
564*d4514f0bSApple OSS Distributions {
565*d4514f0bSApple OSS Distributions 	return p.unsafe_discard_bounds() != nullptr;
566*d4514f0bSApple OSS Distributions }
567*d4514f0bSApple OSS Distributions 
568*d4514f0bSApple OSS Distributions template <typename T, typename Policy>
569*d4514f0bSApple OSS Distributions OS_ALWAYS_INLINE bool
570*d4514f0bSApple OSS Distributions operator==(bounded_ptr<T, Policy> const& p, detail::nullptr_t)
571*d4514f0bSApple OSS Distributions {
572*d4514f0bSApple OSS Distributions 	return p.unsafe_discard_bounds() == nullptr;
573*d4514f0bSApple OSS Distributions }
574*d4514f0bSApple OSS Distributions 
575*d4514f0bSApple OSS Distributions template <typename T, typename Policy>
576*d4514f0bSApple OSS Distributions OS_ALWAYS_INLINE bool
577*d4514f0bSApple OSS Distributions operator!=(bounded_ptr<T, Policy> const& p, detail::nullptr_t)
578*d4514f0bSApple OSS Distributions {
579*d4514f0bSApple OSS Distributions 	return p.unsafe_discard_bounds() != nullptr;
580*d4514f0bSApple OSS Distributions }
581*d4514f0bSApple OSS Distributions 
582*d4514f0bSApple OSS Distributions // Returns whether a `bounded_ptr` points to an address that is {less-than,
583*d4514f0bSApple OSS Distributions // less-than-or-equal-to, greater-than, greater-than-or-equal-to} the address
584*d4514f0bSApple OSS Distributions // held in another `bounded_ptr`.
585*d4514f0bSApple OSS Distributions //
586*d4514f0bSApple OSS Distributions // This doesn't validate the bounds of either `bounded_ptr`, nor does it
587*d4514f0bSApple OSS Distributions // compare those bounds to determine the ordering result. This ordering is
588*d4514f0bSApple OSS Distributions // semantically equivalent to ordering the result of calling `get()` on both
589*d4514f0bSApple OSS Distributions // `bounded_ptr`s.
590*d4514f0bSApple OSS Distributions //
591*d4514f0bSApple OSS Distributions // This ordering is enabled between `bounded_ptr`s whenever the two
592*d4514f0bSApple OSS Distributions // corresponding raw pointer types are orderable. Ordering between a
593*d4514f0bSApple OSS Distributions // raw pointer and a `bounded_ptr` is also allowed, so long as the
594*d4514f0bSApple OSS Distributions // two corresponding raw pointer types are orderable.
595*d4514f0bSApple OSS Distributions //
596*d4514f0bSApple OSS Distributions 
597*d4514f0bSApple OSS Distributions template <typename T, typename U, typename P1, typename P2, typename = detail::WhenOrderable<T*, U*> >
598*d4514f0bSApple OSS Distributions OS_ALWAYS_INLINE bool
599*d4514f0bSApple OSS Distributions operator<(bounded_ptr<T, P1> const& a, bounded_ptr<U, P2> const& b)
600*d4514f0bSApple OSS Distributions {
601*d4514f0bSApple OSS Distributions 	return a.unsafe_discard_bounds() < b.unsafe_discard_bounds();
602*d4514f0bSApple OSS Distributions }
603*d4514f0bSApple OSS Distributions 
604*d4514f0bSApple OSS Distributions template <typename T, typename U, typename P1, typename P2, typename = detail::WhenOrderable<T*, U*> >
605*d4514f0bSApple OSS Distributions OS_ALWAYS_INLINE bool
606*d4514f0bSApple OSS Distributions operator<=(bounded_ptr<T, P1> const& a, bounded_ptr<U, P2> const& b)
607*d4514f0bSApple OSS Distributions {
608*d4514f0bSApple OSS Distributions 	return a.unsafe_discard_bounds() <= b.unsafe_discard_bounds();
609*d4514f0bSApple OSS Distributions }
610*d4514f0bSApple OSS Distributions 
611*d4514f0bSApple OSS Distributions template <typename T, typename U, typename P1, typename P2, typename = detail::WhenOrderable<T*, U*> >
612*d4514f0bSApple OSS Distributions OS_ALWAYS_INLINE bool
613*d4514f0bSApple OSS Distributions operator>(bounded_ptr<T, P1> const& a, bounded_ptr<U, P2> const& b)
614*d4514f0bSApple OSS Distributions {
615*d4514f0bSApple OSS Distributions 	return a.unsafe_discard_bounds() > b.unsafe_discard_bounds();
616*d4514f0bSApple OSS Distributions }
617*d4514f0bSApple OSS Distributions 
618*d4514f0bSApple OSS Distributions template <typename T, typename U, typename P1, typename P2, typename = detail::WhenOrderable<T*, U*> >
619*d4514f0bSApple OSS Distributions OS_ALWAYS_INLINE bool
620*d4514f0bSApple OSS Distributions operator>=(bounded_ptr<T, P1> const& a, bounded_ptr<U, P2> const& b)
621*d4514f0bSApple OSS Distributions {
622*d4514f0bSApple OSS Distributions 	return a.unsafe_discard_bounds() >= b.unsafe_discard_bounds();
623*d4514f0bSApple OSS Distributions }
624*d4514f0bSApple OSS Distributions 
625*d4514f0bSApple OSS Distributions template <typename T, typename U, typename P, typename = detail::WhenOrderable<T*, U*> >
626*d4514f0bSApple OSS Distributions OS_ALWAYS_INLINE bool
627*d4514f0bSApple OSS Distributions operator<(T* a, bounded_ptr<U, P> const& b)
628*d4514f0bSApple OSS Distributions {
629*d4514f0bSApple OSS Distributions 	return a < b.unsafe_discard_bounds();
630*d4514f0bSApple OSS Distributions }
631*d4514f0bSApple OSS Distributions 
632*d4514f0bSApple OSS Distributions template <typename T, typename U, typename P, typename = detail::WhenOrderable<T*, U*> >
633*d4514f0bSApple OSS Distributions OS_ALWAYS_INLINE bool
634*d4514f0bSApple OSS Distributions operator<(bounded_ptr<T, P> const& a, U* b)
635*d4514f0bSApple OSS Distributions {
636*d4514f0bSApple OSS Distributions 	return a.unsafe_discard_bounds() < b;
637*d4514f0bSApple OSS Distributions }
638*d4514f0bSApple OSS Distributions 
639*d4514f0bSApple OSS Distributions template <typename T, typename U, typename P, typename = detail::WhenOrderable<T*, U*> >
640*d4514f0bSApple OSS Distributions OS_ALWAYS_INLINE bool
641*d4514f0bSApple OSS Distributions operator<=(T* a, bounded_ptr<U, P> const& b)
642*d4514f0bSApple OSS Distributions {
643*d4514f0bSApple OSS Distributions 	return a <= b.unsafe_discard_bounds();
644*d4514f0bSApple OSS Distributions }
645*d4514f0bSApple OSS Distributions 
646*d4514f0bSApple OSS Distributions template <typename T, typename U, typename P, typename = detail::WhenOrderable<T*, U*> >
647*d4514f0bSApple OSS Distributions OS_ALWAYS_INLINE bool
648*d4514f0bSApple OSS Distributions operator<=(bounded_ptr<T, P> const& a, U* b)
649*d4514f0bSApple OSS Distributions {
650*d4514f0bSApple OSS Distributions 	return a.unsafe_discard_bounds() <= b;
651*d4514f0bSApple OSS Distributions }
652*d4514f0bSApple OSS Distributions 
653*d4514f0bSApple OSS Distributions template <typename T, typename U, typename P, typename = detail::WhenOrderable<T*, U*> >
654*d4514f0bSApple OSS Distributions OS_ALWAYS_INLINE bool
655*d4514f0bSApple OSS Distributions operator>(T* a, bounded_ptr<U, P> const& b)
656*d4514f0bSApple OSS Distributions {
657*d4514f0bSApple OSS Distributions 	return a > b.unsafe_discard_bounds();
658*d4514f0bSApple OSS Distributions }
659*d4514f0bSApple OSS Distributions 
660*d4514f0bSApple OSS Distributions template <typename T, typename U, typename P, typename = detail::WhenOrderable<T*, U*> >
661*d4514f0bSApple OSS Distributions OS_ALWAYS_INLINE bool
662*d4514f0bSApple OSS Distributions operator>(bounded_ptr<T, P> const& a, U* b)
663*d4514f0bSApple OSS Distributions {
664*d4514f0bSApple OSS Distributions 	return a.unsafe_discard_bounds() > b;
665*d4514f0bSApple OSS Distributions }
666*d4514f0bSApple OSS Distributions 
667*d4514f0bSApple OSS Distributions template <typename T, typename U, typename P, typename = detail::WhenOrderable<T*, U*> >
668*d4514f0bSApple OSS Distributions OS_ALWAYS_INLINE bool
669*d4514f0bSApple OSS Distributions operator>=(T* a, bounded_ptr<U, P> const& b)
670*d4514f0bSApple OSS Distributions {
671*d4514f0bSApple OSS Distributions 	return a >= b.unsafe_discard_bounds();
672*d4514f0bSApple OSS Distributions }
673*d4514f0bSApple OSS Distributions 
674*d4514f0bSApple OSS Distributions template <typename T, typename U, typename P, typename = detail::WhenOrderable<T*, U*> >
675*d4514f0bSApple OSS Distributions OS_ALWAYS_INLINE bool
676*d4514f0bSApple OSS Distributions operator>=(bounded_ptr<T, P> const& a, U* b)
677*d4514f0bSApple OSS Distributions {
678*d4514f0bSApple OSS Distributions 	return a.unsafe_discard_bounds() >= b;
679*d4514f0bSApple OSS Distributions }
680*d4514f0bSApple OSS Distributions 
681*d4514f0bSApple OSS Distributions template <typename T, typename U>
682*d4514f0bSApple OSS Distributions OS_ALWAYS_INLINE T*
683*d4514f0bSApple OSS Distributions reinterpret_pointer_cast(U* p) noexcept
684*d4514f0bSApple OSS Distributions {
685*d4514f0bSApple OSS Distributions 	return reinterpret_cast<T*>(p);
686*d4514f0bSApple OSS Distributions }
687*d4514f0bSApple OSS Distributions 
688*d4514f0bSApple OSS Distributions // Reinterprets a `bounded_ptr` to a type `T` to a `bounded_ptr` to a type `U`.
689*d4514f0bSApple OSS Distributions //
690*d4514f0bSApple OSS Distributions // This is equivalent to `reinterpret_cast`ing the underlying pointer as well
691*d4514f0bSApple OSS Distributions // as the bounds of the original pointer. Like for a raw `reinterpret_cast`,
692*d4514f0bSApple OSS Distributions // no offset adjustment is performed (even if needed, e.g. for derived-to-base
693*d4514f0bSApple OSS Distributions // casts with multiple inheritance). Because this is extremely unsafe, it should
694*d4514f0bSApple OSS Distributions // be used extremely sparingly.
695*d4514f0bSApple OSS Distributions template <typename T, typename U, typename Policy>
696*d4514f0bSApple OSS Distributions OS_ALWAYS_INLINE bounded_ptr<T, Policy>
697*d4514f0bSApple OSS Distributions reinterpret_pointer_cast(bounded_ptr<U, Policy> const& p) noexcept
698*d4514f0bSApple OSS Distributions {
699*d4514f0bSApple OSS Distributions 	using CharType = detail::copy_cv_t<T, char>;
700*d4514f0bSApple OSS Distributions 	CharType* new_begin = reinterpret_cast<CharType*>(p.base_);
701*d4514f0bSApple OSS Distributions 	CharType* new_end = new_begin + p.count_;
702*d4514f0bSApple OSS Distributions 	return bounded_ptr<T, Policy>(reinterpret_cast<T*>(p.get_ptr_()),
703*d4514f0bSApple OSS Distributions 	           reinterpret_cast<T const*>(new_begin),
704*d4514f0bSApple OSS Distributions 	           reinterpret_cast<T const*>(new_end));
705*d4514f0bSApple OSS Distributions }
706*d4514f0bSApple OSS Distributions } // end namespace libkern
707*d4514f0bSApple OSS Distributions 
708*d4514f0bSApple OSS Distributions #endif /* !TAPI */
709*d4514f0bSApple OSS Distributions 
710*d4514f0bSApple OSS Distributions #endif // !XNU_LIBKERN_LIBKERN_CXX_BOUNDED_PTR_H
711