1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sw=4 et tw=99 ft=cpp:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at:
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
17 * The Original Code is Mozilla Code.
19 * The Initial Developer of the Original Code is
20 * The Mozilla Foundation
21 * Portions created by the Initial Developer are Copyright (C) 2011
22 * the Initial Developer. All Rights Reserved.
25 * Jeff Walden <jwalden+code@mit.edu> (original author)
27 * Alternatively, the contents of this file may be used under the terms of
28 * either the GNU General Public License Version 2 or later (the "GPL"), or
29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
42 * Implements a smart pointer asserted to remain within a range specified at
46 #ifndef mozilla_RangedPtr_h_
47 #define mozilla_RangedPtr_h_
49 #include "mozilla/Assertions.h"
50 #include "mozilla/Attributes.h"
51 #include "mozilla/Util.h"
56 * RangedPtr is a smart pointer restricted to an address range specified at
57 * creation. The pointer (and any smart pointers derived from it) must remain
58 * within the range [start, end] (inclusive of end to facilitate use as
59 * sentinels). Dereferencing or indexing into the pointer (or pointers derived
60 * from it) must remain within the range [start, end). All the standard pointer
61 * operators are defined on it; in debug builds these operations assert that the
62 * range specified at construction is respected.
64 * In theory passing a smart pointer instance as an argument can be slightly
65 * slower than passing a T* (due to ABI requirements for passing structs versus
66 * passing pointers), if the method being called isn't inlined. If you are in
67 * extremely performance-critical code, you may want to be careful using this
68 * smart pointer as an argument type.
70 * RangedPtr<T> intentionally does not implicitly convert to T*. Use get() to
71 * explicitly convert to T*. Keep in mind that the raw pointer of course won't
72 * implement bounds checking in debug builds.
85 MOZ_ASSERT(rangeStart
<= ptr
);
86 MOZ_ASSERT(ptr
<= rangeEnd
);
89 /* Creates a new pointer for |ptr|, restricted to this pointer's range. */
90 RangedPtr
<T
> create(T
*ptr
) const {
92 return RangedPtr
<T
>(ptr
, rangeStart
, rangeEnd
);
94 return RangedPtr
<T
>(ptr
, NULL
, size_t(0));
99 RangedPtr(T
* p
, T
* start
, T
* end
)
102 , rangeStart(start
), rangeEnd(end
)
105 MOZ_ASSERT(rangeStart
<= rangeEnd
);
108 RangedPtr(T
* p
, T
* start
, size_t length
)
111 , rangeStart(start
), rangeEnd(start
+ length
)
114 MOZ_ASSERT(length
<= size_t(-1) / sizeof(T
));
115 MOZ_ASSERT(uintptr_t(rangeStart
) + length
* sizeof(T
) >= uintptr_t(rangeStart
));
119 /* Equivalent to RangedPtr(p, p, length). */
120 RangedPtr(T
* p
, size_t length
)
123 , rangeStart(p
), rangeEnd(p
+ length
)
126 MOZ_ASSERT(length
<= size_t(-1) / sizeof(T
));
127 MOZ_ASSERT(uintptr_t(rangeStart
) + length
* sizeof(T
) >= uintptr_t(rangeStart
));
131 /* Equivalent to RangedPtr(arr, arr, N). */
136 , rangeStart(arr
), rangeEnd(arr
+ N
)
147 * You can only assign one RangedPtr into another if the two pointers have
148 * the same valid range:
150 * char arr1[] = "hi";
151 * char arr2[] = "bye";
152 * RangedPtr<char> p1(arr1, 2);
153 * p1 = RangedPtr<char>(arr1 + 1, arr1, arr1 + 2); // works
154 * p1 = RangedPtr<char>(arr2, 3); // asserts
156 RangedPtr
<T
>& operator=(const RangedPtr
<T
>& other
) {
157 MOZ_ASSERT(rangeStart
== other
.rangeStart
);
158 MOZ_ASSERT(rangeEnd
== other
.rangeEnd
);
164 RangedPtr
<T
> operator+(size_t inc
) {
165 MOZ_ASSERT(inc
<= size_t(-1) / sizeof(T
));
166 MOZ_ASSERT(ptr
+ inc
> ptr
);
167 return create(ptr
+ inc
);
170 RangedPtr
<T
> operator-(size_t dec
) {
171 MOZ_ASSERT(dec
<= size_t(-1) / sizeof(T
));
172 MOZ_ASSERT(ptr
- dec
< ptr
);
173 return create(ptr
- dec
);
177 * You can assign a raw pointer into a RangedPtr if the raw pointer is
178 * within the range specified at creation.
180 template <typename U
>
181 RangedPtr
<T
>& operator=(U
* p
) {
186 template <typename U
>
187 RangedPtr
<T
>& operator=(const RangedPtr
<U
>& p
) {
188 MOZ_ASSERT(rangeStart
<= p
.ptr
);
189 MOZ_ASSERT(p
.ptr
<= rangeEnd
);
195 RangedPtr
<T
>& operator++() {
199 RangedPtr
<T
> operator++(int) {
200 RangedPtr
<T
> rcp
= *this;
205 RangedPtr
<T
>& operator--() {
209 RangedPtr
<T
> operator--(int) {
210 RangedPtr
<T
> rcp
= *this;
215 RangedPtr
<T
>& operator+=(size_t inc
) {
216 this->operator=<T
>(*this + inc
);
220 RangedPtr
<T
>& operator-=(size_t dec
) {
221 this->operator=<T
>(*this - dec
);
225 T
& operator[](int index
) const {
226 MOZ_ASSERT(size_t(index
> 0 ? index
: -index
) <= size_t(-1) / sizeof(T
));
227 return *create(ptr
+ index
);
230 T
& operator*() const {
234 template <typename U
>
235 bool operator==(const RangedPtr
<U
>& other
) const {
236 return ptr
== other
.ptr
;
238 template <typename U
>
239 bool operator!=(const RangedPtr
<U
>& other
) const {
240 return !(*this == other
);
244 bool operator==(const U
* u
) const {
248 bool operator!=(const U
* u
) const {
249 return !(*this == u
);
252 template <typename U
>
253 bool operator<(const RangedPtr
<U
>& other
) const {
254 return ptr
< other
.ptr
;
256 template <typename U
>
257 bool operator<=(const RangedPtr
<U
>& other
) const {
258 return ptr
<= other
.ptr
;
261 template <typename U
>
262 bool operator>(const RangedPtr
<U
>& other
) const {
263 return ptr
> other
.ptr
;
265 template <typename U
>
266 bool operator>=(const RangedPtr
<U
>& other
) const {
267 return ptr
>= other
.ptr
;
270 size_t operator-(const RangedPtr
<T
>& other
) const {
271 MOZ_ASSERT(ptr
>= other
.ptr
);
272 return PointerRangeSize(other
.ptr
, ptr
);
276 RangedPtr() MOZ_DELETE
;
277 T
* operator&() MOZ_DELETE
;
278 operator T
*() const MOZ_DELETE
;
281 } /* namespace mozilla */
283 #endif /* mozilla_RangedPtr_h_ */