1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 * Implements a smart pointer asserted to remain within a range specified at
11 #ifndef mozilla_RangedPtr_h_
12 #define mozilla_RangedPtr_h_
14 #include "mozilla/Assertions.h"
15 #include "mozilla/Attributes.h"
16 #include "mozilla/Util.h"
21 * RangedPtr is a smart pointer restricted to an address range specified at
22 * creation. The pointer (and any smart pointers derived from it) must remain
23 * within the range [start, end] (inclusive of end to facilitate use as
24 * sentinels). Dereferencing or indexing into the pointer (or pointers derived
25 * from it) must remain within the range [start, end). All the standard pointer
26 * operators are defined on it; in debug builds these operations assert that the
27 * range specified at construction is respected.
29 * In theory passing a smart pointer instance as an argument can be slightly
30 * slower than passing a T* (due to ABI requirements for passing structs versus
31 * passing pointers), if the method being called isn't inlined. If you are in
32 * extremely performance-critical code, you may want to be careful using this
33 * smart pointer as an argument type.
35 * RangedPtr<T> intentionally does not implicitly convert to T*. Use get() to
36 * explicitly convert to T*. Keep in mind that the raw pointer of course won't
37 * implement bounds checking in debug builds.
50 MOZ_ASSERT(rangeStart
<= ptr
);
51 MOZ_ASSERT(ptr
<= rangeEnd
);
54 /* Creates a new pointer for |ptr|, restricted to this pointer's range. */
55 RangedPtr
<T
> create(T
*ptr
) const {
57 return RangedPtr
<T
>(ptr
, rangeStart
, rangeEnd
);
59 return RangedPtr
<T
>(ptr
, NULL
, size_t(0));
64 RangedPtr(T
* p
, T
* start
, T
* end
)
67 , rangeStart(start
), rangeEnd(end
)
70 MOZ_ASSERT(rangeStart
<= rangeEnd
);
73 RangedPtr(T
* p
, T
* start
, size_t length
)
76 , rangeStart(start
), rangeEnd(start
+ length
)
79 MOZ_ASSERT(length
<= size_t(-1) / sizeof(T
));
80 MOZ_ASSERT(uintptr_t(rangeStart
) + length
* sizeof(T
) >= uintptr_t(rangeStart
));
84 /* Equivalent to RangedPtr(p, p, length). */
85 RangedPtr(T
* p
, size_t length
)
88 , rangeStart(p
), rangeEnd(p
+ length
)
91 MOZ_ASSERT(length
<= size_t(-1) / sizeof(T
));
92 MOZ_ASSERT(uintptr_t(rangeStart
) + length
* sizeof(T
) >= uintptr_t(rangeStart
));
96 /* Equivalent to RangedPtr(arr, arr, N). */
101 , rangeStart(arr
), rangeEnd(arr
+ N
)
112 * You can only assign one RangedPtr into another if the two pointers have
113 * the same valid range:
115 * char arr1[] = "hi";
116 * char arr2[] = "bye";
117 * RangedPtr<char> p1(arr1, 2);
118 * p1 = RangedPtr<char>(arr1 + 1, arr1, arr1 + 2); // works
119 * p1 = RangedPtr<char>(arr2, 3); // asserts
121 RangedPtr
<T
>& operator=(const RangedPtr
<T
>& other
) {
122 MOZ_ASSERT(rangeStart
== other
.rangeStart
);
123 MOZ_ASSERT(rangeEnd
== other
.rangeEnd
);
129 RangedPtr
<T
> operator+(size_t inc
) {
130 MOZ_ASSERT(inc
<= size_t(-1) / sizeof(T
));
131 MOZ_ASSERT(ptr
+ inc
>= ptr
);
132 return create(ptr
+ inc
);
135 RangedPtr
<T
> operator-(size_t dec
) {
136 MOZ_ASSERT(dec
<= size_t(-1) / sizeof(T
));
137 MOZ_ASSERT(ptr
- dec
<= ptr
);
138 return create(ptr
- dec
);
142 * You can assign a raw pointer into a RangedPtr if the raw pointer is
143 * within the range specified at creation.
145 template <typename U
>
146 RangedPtr
<T
>& operator=(U
* p
) {
151 template <typename U
>
152 RangedPtr
<T
>& operator=(const RangedPtr
<U
>& p
) {
153 MOZ_ASSERT(rangeStart
<= p
.ptr
);
154 MOZ_ASSERT(p
.ptr
<= rangeEnd
);
160 RangedPtr
<T
>& operator++() {
164 RangedPtr
<T
> operator++(int) {
165 RangedPtr
<T
> rcp
= *this;
170 RangedPtr
<T
>& operator--() {
174 RangedPtr
<T
> operator--(int) {
175 RangedPtr
<T
> rcp
= *this;
180 RangedPtr
<T
>& operator+=(size_t inc
) {
185 RangedPtr
<T
>& operator-=(size_t dec
) {
190 T
& operator[](int index
) const {
191 MOZ_ASSERT(size_t(index
> 0 ? index
: -index
) <= size_t(-1) / sizeof(T
));
192 return *create(ptr
+ index
);
195 T
& operator*() const {
199 template <typename U
>
200 bool operator==(const RangedPtr
<U
>& other
) const {
201 return ptr
== other
.ptr
;
203 template <typename U
>
204 bool operator!=(const RangedPtr
<U
>& other
) const {
205 return !(*this == other
);
209 bool operator==(const U
* u
) const {
213 bool operator!=(const U
* u
) const {
214 return !(*this == u
);
217 template <typename U
>
218 bool operator<(const RangedPtr
<U
>& other
) const {
219 return ptr
< other
.ptr
;
221 template <typename U
>
222 bool operator<=(const RangedPtr
<U
>& other
) const {
223 return ptr
<= other
.ptr
;
226 template <typename U
>
227 bool operator>(const RangedPtr
<U
>& other
) const {
228 return ptr
> other
.ptr
;
230 template <typename U
>
231 bool operator>=(const RangedPtr
<U
>& other
) const {
232 return ptr
>= other
.ptr
;
235 size_t operator-(const RangedPtr
<T
>& other
) const {
236 MOZ_ASSERT(ptr
>= other
.ptr
);
237 return PointerRangeSize(other
.ptr
, ptr
);
241 RangedPtr() MOZ_DELETE
;
242 T
* operator&() MOZ_DELETE
;
243 operator T
*() const MOZ_DELETE
;
246 } /* namespace mozilla */
248 #endif /* mozilla_RangedPtr_h_ */