bug 816059 - properly reset blocklist in browser-chrome tests r=jaws
[gecko.git] / mfbt / RangedPtr.h
blobadecf7c1a0974d5eccd0b41e12beca505b9a0893
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/. */
6 /*
7 * Implements a smart pointer asserted to remain within a range specified at
8 * construction.
9 */
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"
18 namespace mozilla {
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.
39 template<typename T>
40 class RangedPtr
42 T* ptr;
44 #ifdef DEBUG
45 T* const rangeStart;
46 T* const rangeEnd;
47 #endif
49 void checkSanity() {
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 {
56 #ifdef DEBUG
57 return RangedPtr<T>(ptr, rangeStart, rangeEnd);
58 #else
59 return RangedPtr<T>(ptr, NULL, size_t(0));
60 #endif
63 public:
64 RangedPtr(T* p, T* start, T* end)
65 : ptr(p)
66 #ifdef DEBUG
67 , rangeStart(start), rangeEnd(end)
68 #endif
70 MOZ_ASSERT(rangeStart <= rangeEnd);
71 checkSanity();
73 RangedPtr(T* p, T* start, size_t length)
74 : ptr(p)
75 #ifdef DEBUG
76 , rangeStart(start), rangeEnd(start + length)
77 #endif
79 MOZ_ASSERT(length <= size_t(-1) / sizeof(T));
80 MOZ_ASSERT(uintptr_t(rangeStart) + length * sizeof(T) >= uintptr_t(rangeStart));
81 checkSanity();
84 /* Equivalent to RangedPtr(p, p, length). */
85 RangedPtr(T* p, size_t length)
86 : ptr(p)
87 #ifdef DEBUG
88 , rangeStart(p), rangeEnd(p + length)
89 #endif
91 MOZ_ASSERT(length <= size_t(-1) / sizeof(T));
92 MOZ_ASSERT(uintptr_t(rangeStart) + length * sizeof(T) >= uintptr_t(rangeStart));
93 checkSanity();
96 /* Equivalent to RangedPtr(arr, arr, N). */
97 template<size_t N>
98 RangedPtr(T arr[N])
99 : ptr(arr)
100 #ifdef DEBUG
101 , rangeStart(arr), rangeEnd(arr + N)
102 #endif
104 checkSanity();
107 T* get() const {
108 return ptr;
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);
124 ptr = other.ptr;
125 checkSanity();
126 return *this;
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) {
147 *this = create(p);
148 return *this;
151 template <typename U>
152 RangedPtr<T>& operator=(const RangedPtr<U>& p) {
153 MOZ_ASSERT(rangeStart <= p.ptr);
154 MOZ_ASSERT(p.ptr <= rangeEnd);
155 ptr = p.ptr;
156 checkSanity();
157 return *this;
160 RangedPtr<T>& operator++() {
161 return (*this += 1);
164 RangedPtr<T> operator++(int) {
165 RangedPtr<T> rcp = *this;
166 ++*this;
167 return rcp;
170 RangedPtr<T>& operator--() {
171 return (*this -= 1);
174 RangedPtr<T> operator--(int) {
175 RangedPtr<T> rcp = *this;
176 --*this;
177 return rcp;
180 RangedPtr<T>& operator+=(size_t inc) {
181 *this = *this + inc;
182 return *this;
185 RangedPtr<T>& operator-=(size_t dec) {
186 *this = *this - dec;
187 return *this;
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 {
196 return *ptr;
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);
208 template<typename U>
209 bool operator==(const U* u) const {
210 return ptr == u;
212 template<typename U>
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);
240 private:
241 RangedPtr() MOZ_DELETE;
242 T* operator&() MOZ_DELETE;
243 operator T*() const MOZ_DELETE;
246 } /* namespace mozilla */
248 #endif /* mozilla_RangedPtr_h_ */