~ubuntu-branches/ubuntu/vivid/mozjs24/vivid

« back to all changes in this revision

Viewing changes to mfbt/RangedPtr.h

  • Committer: Package Import Robot
  • Author(s): Tim Lunn
  • Date: 2014-02-11 21:55:34 UTC
  • Revision ID: package-import@ubuntu.com-20140211215534-m1zyq5aj59md3y07
Tags: upstream-24.2.0
ImportĀ upstreamĀ versionĀ 24.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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/. */
 
5
 
 
6
/*
 
7
 * Implements a smart pointer asserted to remain within a range specified at
 
8
 * construction.
 
9
 */
 
10
 
 
11
#ifndef mozilla_RangedPtr_h_
 
12
#define mozilla_RangedPtr_h_
 
13
 
 
14
#include "mozilla/Assertions.h"
 
15
#include "mozilla/Attributes.h"
 
16
#include "mozilla/Util.h"
 
17
 
 
18
namespace mozilla {
 
19
 
 
20
/*
 
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.
 
28
 *
 
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.
 
34
 *
 
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.
 
38
 */
 
39
template<typename T>
 
40
class RangedPtr
 
41
{
 
42
    T* ptr;
 
43
 
 
44
#ifdef DEBUG
 
45
    T* const rangeStart;
 
46
    T* const rangeEnd;
 
47
#endif
 
48
 
 
49
    typedef void (RangedPtr::* ConvertibleToBool)();
 
50
    void nonNull() {}
 
51
 
 
52
    void checkSanity() {
 
53
      MOZ_ASSERT(rangeStart <= ptr);
 
54
      MOZ_ASSERT(ptr <= rangeEnd);
 
55
    }
 
56
 
 
57
    /* Creates a new pointer for |p|, restricted to this pointer's range. */
 
58
    RangedPtr<T> create(T *p) const {
 
59
#ifdef DEBUG
 
60
      return RangedPtr<T>(p, rangeStart, rangeEnd);
 
61
#else
 
62
      return RangedPtr<T>(p, NULL, size_t(0));
 
63
#endif
 
64
    }
 
65
 
 
66
    uintptr_t asUintptr() const { return uintptr_t(ptr); }
 
67
 
 
68
  public:
 
69
    RangedPtr(T* p, T* start, T* end)
 
70
      : ptr(p)
 
71
#ifdef DEBUG
 
72
      , rangeStart(start), rangeEnd(end)
 
73
#endif
 
74
    {
 
75
      MOZ_ASSERT(rangeStart <= rangeEnd);
 
76
      checkSanity();
 
77
    }
 
78
    RangedPtr(T* p, T* start, size_t length)
 
79
      : ptr(p)
 
80
#ifdef DEBUG
 
81
      , rangeStart(start), rangeEnd(start + length)
 
82
#endif
 
83
    {
 
84
      MOZ_ASSERT(length <= size_t(-1) / sizeof(T));
 
85
      MOZ_ASSERT(uintptr_t(rangeStart) + length * sizeof(T) >= uintptr_t(rangeStart));
 
86
      checkSanity();
 
87
    }
 
88
 
 
89
    /* Equivalent to RangedPtr(p, p, length). */
 
90
    RangedPtr(T* p, size_t length)
 
91
      : ptr(p)
 
92
#ifdef DEBUG
 
93
      , rangeStart(p), rangeEnd(p + length)
 
94
#endif
 
95
    {
 
96
      MOZ_ASSERT(length <= size_t(-1) / sizeof(T));
 
97
      MOZ_ASSERT(uintptr_t(rangeStart) + length * sizeof(T) >= uintptr_t(rangeStart));
 
98
      checkSanity();
 
99
    }
 
100
 
 
101
    /* Equivalent to RangedPtr(arr, arr, N). */
 
102
    template<size_t N>
 
103
    RangedPtr(T (&arr)[N])
 
104
      : ptr(arr)
 
105
#ifdef DEBUG
 
106
      , rangeStart(arr), rangeEnd(arr + N)
 
107
#endif
 
108
    {
 
109
      checkSanity();
 
110
    }
 
111
 
 
112
    T* get() const {
 
113
      return ptr;
 
114
    }
 
115
 
 
116
    operator ConvertibleToBool() const { return ptr ? &RangedPtr::nonNull : 0; }
 
117
 
 
118
    /*
 
119
     * You can only assign one RangedPtr into another if the two pointers have
 
120
     * the same valid range:
 
121
     *
 
122
     *   char arr1[] = "hi";
 
123
     *   char arr2[] = "bye";
 
124
     *   RangedPtr<char> p1(arr1, 2);
 
125
     *   p1 = RangedPtr<char>(arr1 + 1, arr1, arr1 + 2); // works
 
126
     *   p1 = RangedPtr<char>(arr2, 3);                  // asserts
 
127
     */
 
128
    RangedPtr<T>& operator=(const RangedPtr<T>& other) {
 
129
      MOZ_ASSERT(rangeStart == other.rangeStart);
 
130
      MOZ_ASSERT(rangeEnd == other.rangeEnd);
 
131
      ptr = other.ptr;
 
132
      checkSanity();
 
133
      return *this;
 
134
    }
 
135
 
 
136
    RangedPtr<T> operator+(size_t inc) {
 
137
      MOZ_ASSERT(inc <= size_t(-1) / sizeof(T));
 
138
      MOZ_ASSERT(asUintptr() + inc * sizeof(T) >= asUintptr());
 
139
      return create(ptr + inc);
 
140
    }
 
141
 
 
142
    RangedPtr<T> operator-(size_t dec) {
 
143
      MOZ_ASSERT(dec <= size_t(-1) / sizeof(T));
 
144
      MOZ_ASSERT(asUintptr() - dec * sizeof(T) <= asUintptr());
 
145
      return create(ptr - dec);
 
146
    }
 
147
 
 
148
    /*
 
149
     * You can assign a raw pointer into a RangedPtr if the raw pointer is
 
150
     * within the range specified at creation.
 
151
     */
 
152
    template <typename U>
 
153
    RangedPtr<T>& operator=(U* p) {
 
154
      *this = create(p);
 
155
      return *this;
 
156
    }
 
157
 
 
158
    template <typename U>
 
159
    RangedPtr<T>& operator=(const RangedPtr<U>& p) {
 
160
      MOZ_ASSERT(rangeStart <= p.ptr);
 
161
      MOZ_ASSERT(p.ptr <= rangeEnd);
 
162
      ptr = p.ptr;
 
163
      checkSanity();
 
164
      return *this;
 
165
    }
 
166
 
 
167
    RangedPtr<T>& operator++() {
 
168
      return (*this += 1);
 
169
    }
 
170
 
 
171
    RangedPtr<T> operator++(int) {
 
172
      RangedPtr<T> rcp = *this;
 
173
      ++*this;
 
174
      return rcp;
 
175
    }
 
176
 
 
177
    RangedPtr<T>& operator--() {
 
178
      return (*this -= 1);
 
179
    }
 
180
 
 
181
    RangedPtr<T> operator--(int) {
 
182
      RangedPtr<T> rcp = *this;
 
183
      --*this;
 
184
      return rcp;
 
185
    }
 
186
 
 
187
    RangedPtr<T>& operator+=(size_t inc) {
 
188
      *this = *this + inc;
 
189
      return *this;
 
190
    }
 
191
 
 
192
    RangedPtr<T>& operator-=(size_t dec) {
 
193
      *this = *this - dec;
 
194
      return *this;
 
195
    }
 
196
 
 
197
    T& operator[](int index) const {
 
198
      MOZ_ASSERT(size_t(index > 0 ? index : -index) <= size_t(-1) / sizeof(T));
 
199
      return *create(ptr + index);
 
200
    }
 
201
 
 
202
    T& operator*() const {
 
203
      return *ptr;
 
204
    }
 
205
 
 
206
    template <typename U>
 
207
    bool operator==(const RangedPtr<U>& other) const {
 
208
      return ptr == other.ptr;
 
209
    }
 
210
    template <typename U>
 
211
    bool operator!=(const RangedPtr<U>& other) const {
 
212
      return !(*this == other);
 
213
    }
 
214
 
 
215
    template<typename U>
 
216
    bool operator==(const U* u) const {
 
217
      return ptr == u;
 
218
    }
 
219
    template<typename U>
 
220
    bool operator!=(const U* u) const {
 
221
      return !(*this == u);
 
222
    }
 
223
 
 
224
    template <typename U>
 
225
    bool operator<(const RangedPtr<U>& other) const {
 
226
      return ptr < other.ptr;
 
227
    }
 
228
    template <typename U>
 
229
    bool operator<=(const RangedPtr<U>& other) const {
 
230
      return ptr <= other.ptr;
 
231
    }
 
232
 
 
233
    template <typename U>
 
234
    bool operator>(const RangedPtr<U>& other) const {
 
235
      return ptr > other.ptr;
 
236
    }
 
237
    template <typename U>
 
238
    bool operator>=(const RangedPtr<U>& other) const {
 
239
      return ptr >= other.ptr;
 
240
    }
 
241
 
 
242
    size_t operator-(const RangedPtr<T>& other) const {
 
243
      MOZ_ASSERT(ptr >= other.ptr);
 
244
      return PointerRangeSize(other.ptr, ptr);
 
245
    }
 
246
 
 
247
  private:
 
248
    RangedPtr() MOZ_DELETE;
 
249
    T* operator&() MOZ_DELETE;
 
250
};
 
251
 
 
252
} /* namespace mozilla */
 
253
 
 
254
#endif  /* mozilla_RangedPtr_h_ */