Bug 986933 - Add DeallocGrallocBuffer() r=nical
[gecko.git] / mfbt / RangedPtr.h
blob4594fc5b79d51f14a764dfa69ff4d33d00fd09e1
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /*
8 * Implements a smart pointer asserted to remain within a range specified at
9 * construction.
12 #ifndef mozilla_RangedPtr_h
13 #define mozilla_RangedPtr_h
15 #include "mozilla/ArrayUtils.h"
16 #include "mozilla/Assertions.h"
17 #include "mozilla/Attributes.h"
18 #include "mozilla/NullPtr.h"
20 #include <stdint.h>
22 namespace mozilla {
25 * RangedPtr is a smart pointer restricted to an address range specified at
26 * creation. The pointer (and any smart pointers derived from it) must remain
27 * within the range [start, end] (inclusive of end to facilitate use as
28 * sentinels). Dereferencing or indexing into the pointer (or pointers derived
29 * from it) must remain within the range [start, end). All the standard pointer
30 * operators are defined on it; in debug builds these operations assert that the
31 * range specified at construction is respected.
33 * In theory passing a smart pointer instance as an argument can be slightly
34 * slower than passing a T* (due to ABI requirements for passing structs versus
35 * passing pointers), if the method being called isn't inlined. If you are in
36 * extremely performance-critical code, you may want to be careful using this
37 * smart pointer as an argument type.
39 * RangedPtr<T> intentionally does not implicitly convert to T*. Use get() to
40 * explicitly convert to T*. Keep in mind that the raw pointer of course won't
41 * implement bounds checking in debug builds.
43 template<typename T>
44 class RangedPtr
46 T* ptr;
48 #ifdef DEBUG
49 T* const rangeStart;
50 T* const rangeEnd;
51 #endif
53 typedef void (RangedPtr::* ConvertibleToBool)();
54 void nonNull() {}
56 void checkSanity() {
57 MOZ_ASSERT(rangeStart <= ptr);
58 MOZ_ASSERT(ptr <= rangeEnd);
61 /* Creates a new pointer for |p|, restricted to this pointer's range. */
62 RangedPtr<T> create(T *p) const {
63 #ifdef DEBUG
64 return RangedPtr<T>(p, rangeStart, rangeEnd);
65 #else
66 return RangedPtr<T>(p, nullptr, size_t(0));
67 #endif
70 uintptr_t asUintptr() const { return uintptr_t(ptr); }
72 public:
73 RangedPtr(T* p, T* start, T* end)
74 : ptr(p)
75 #ifdef DEBUG
76 , rangeStart(start), rangeEnd(end)
77 #endif
79 MOZ_ASSERT(rangeStart <= rangeEnd);
80 checkSanity();
82 RangedPtr(T* p, T* start, size_t length)
83 : ptr(p)
84 #ifdef DEBUG
85 , rangeStart(start), rangeEnd(start + length)
86 #endif
88 MOZ_ASSERT(length <= size_t(-1) / sizeof(T));
89 MOZ_ASSERT(uintptr_t(rangeStart) + length * sizeof(T) >= uintptr_t(rangeStart));
90 checkSanity();
93 /* Equivalent to RangedPtr(p, p, length). */
94 RangedPtr(T* p, size_t length)
95 : ptr(p)
96 #ifdef DEBUG
97 , rangeStart(p), rangeEnd(p + length)
98 #endif
100 MOZ_ASSERT(length <= size_t(-1) / sizeof(T));
101 MOZ_ASSERT(uintptr_t(rangeStart) + length * sizeof(T) >= uintptr_t(rangeStart));
102 checkSanity();
105 /* Equivalent to RangedPtr(arr, arr, N). */
106 template<size_t N>
107 RangedPtr(T (&arr)[N])
108 : ptr(arr)
109 #ifdef DEBUG
110 , rangeStart(arr), rangeEnd(arr + N)
111 #endif
113 checkSanity();
116 T* get() const {
117 return ptr;
120 operator ConvertibleToBool() const { return ptr ? &RangedPtr::nonNull : 0; }
123 * You can only assign one RangedPtr into another if the two pointers have
124 * the same valid range:
126 * char arr1[] = "hi";
127 * char arr2[] = "bye";
128 * RangedPtr<char> p1(arr1, 2);
129 * p1 = RangedPtr<char>(arr1 + 1, arr1, arr1 + 2); // works
130 * p1 = RangedPtr<char>(arr2, 3); // asserts
132 RangedPtr<T>& operator=(const RangedPtr<T>& other) {
133 MOZ_ASSERT(rangeStart == other.rangeStart);
134 MOZ_ASSERT(rangeEnd == other.rangeEnd);
135 ptr = other.ptr;
136 checkSanity();
137 return *this;
140 RangedPtr<T> operator+(size_t inc) {
141 MOZ_ASSERT(inc <= size_t(-1) / sizeof(T));
142 MOZ_ASSERT(asUintptr() + inc * sizeof(T) >= asUintptr());
143 return create(ptr + inc);
146 RangedPtr<T> operator-(size_t dec) {
147 MOZ_ASSERT(dec <= size_t(-1) / sizeof(T));
148 MOZ_ASSERT(asUintptr() - dec * sizeof(T) <= asUintptr());
149 return create(ptr - dec);
153 * You can assign a raw pointer into a RangedPtr if the raw pointer is
154 * within the range specified at creation.
156 template <typename U>
157 RangedPtr<T>& operator=(U* p) {
158 *this = create(p);
159 return *this;
162 template <typename U>
163 RangedPtr<T>& operator=(const RangedPtr<U>& p) {
164 MOZ_ASSERT(rangeStart <= p.ptr);
165 MOZ_ASSERT(p.ptr <= rangeEnd);
166 ptr = p.ptr;
167 checkSanity();
168 return *this;
171 RangedPtr<T>& operator++() {
172 return (*this += 1);
175 RangedPtr<T> operator++(int) {
176 RangedPtr<T> rcp = *this;
177 ++*this;
178 return rcp;
181 RangedPtr<T>& operator--() {
182 return (*this -= 1);
185 RangedPtr<T> operator--(int) {
186 RangedPtr<T> rcp = *this;
187 --*this;
188 return rcp;
191 RangedPtr<T>& operator+=(size_t inc) {
192 *this = *this + inc;
193 return *this;
196 RangedPtr<T>& operator-=(size_t dec) {
197 *this = *this - dec;
198 return *this;
201 T& operator[](int index) const {
202 MOZ_ASSERT(size_t(index > 0 ? index : -index) <= size_t(-1) / sizeof(T));
203 return *create(ptr + index);
206 T& operator*() const {
207 MOZ_ASSERT(ptr >= rangeStart);
208 MOZ_ASSERT(ptr < rangeEnd);
209 return *ptr;
212 template <typename U>
213 bool operator==(const RangedPtr<U>& other) const {
214 return ptr == other.ptr;
216 template <typename U>
217 bool operator!=(const RangedPtr<U>& other) const {
218 return !(*this == other);
221 template<typename U>
222 bool operator==(const U* u) const {
223 return ptr == u;
225 template<typename U>
226 bool operator!=(const U* u) const {
227 return !(*this == u);
230 template <typename U>
231 bool operator<(const RangedPtr<U>& other) const {
232 return ptr < other.ptr;
234 template <typename U>
235 bool operator<=(const RangedPtr<U>& other) const {
236 return ptr <= other.ptr;
239 template <typename U>
240 bool operator>(const RangedPtr<U>& other) const {
241 return ptr > other.ptr;
243 template <typename U>
244 bool operator>=(const RangedPtr<U>& other) const {
245 return ptr >= other.ptr;
248 size_t operator-(const RangedPtr<T>& other) const {
249 MOZ_ASSERT(ptr >= other.ptr);
250 return PointerRangeSize(other.ptr, ptr);
253 private:
254 RangedPtr() MOZ_DELETE;
255 T* operator&() MOZ_DELETE;
258 } /* namespace mozilla */
260 #endif /* mozilla_RangedPtr_h */