~ubuntu-branches/ubuntu/saucy/mozjs17/saucy

« back to all changes in this revision

Viewing changes to mfbt/RangedPtr.h

  • Committer: Package Import Robot
  • Author(s): Rico Tzschichholz
  • Date: 2013-05-25 12:24:23 UTC
  • Revision ID: package-import@ubuntu.com-20130525122423-zmxucrhtensw90xy
Tags: upstream-17.0.0
ImportĀ upstreamĀ versionĀ 17.0.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
    void checkSanity() {
 
50
      MOZ_ASSERT(rangeStart <= ptr);
 
51
      MOZ_ASSERT(ptr <= rangeEnd);
 
52
    }
 
53
 
 
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
 
61
    }
 
62
 
 
63
  public:
 
64
    RangedPtr(T* p, T* start, T* end)
 
65
      : ptr(p)
 
66
#ifdef DEBUG
 
67
      , rangeStart(start), rangeEnd(end)
 
68
#endif
 
69
    {
 
70
      MOZ_ASSERT(rangeStart <= rangeEnd);
 
71
      checkSanity();
 
72
    }
 
73
    RangedPtr(T* p, T* start, size_t length)
 
74
      : ptr(p)
 
75
#ifdef DEBUG
 
76
      , rangeStart(start), rangeEnd(start + length)
 
77
#endif
 
78
    {
 
79
      MOZ_ASSERT(length <= size_t(-1) / sizeof(T));
 
80
      MOZ_ASSERT(uintptr_t(rangeStart) + length * sizeof(T) >= uintptr_t(rangeStart));
 
81
      checkSanity();
 
82
    }
 
83
 
 
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
 
90
    {
 
91
      MOZ_ASSERT(length <= size_t(-1) / sizeof(T));
 
92
      MOZ_ASSERT(uintptr_t(rangeStart) + length * sizeof(T) >= uintptr_t(rangeStart));
 
93
      checkSanity();
 
94
    }
 
95
 
 
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
 
103
    {
 
104
      checkSanity();
 
105
    }
 
106
 
 
107
    T* get() const {
 
108
      return ptr;
 
109
    }
 
110
 
 
111
    /*
 
112
     * You can only assign one RangedPtr into another if the two pointers have
 
113
     * the same valid range:
 
114
     *
 
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
 
120
     */
 
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;
 
127
    }
 
128
 
 
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);
 
133
    }
 
134
 
 
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);
 
139
    }
 
140
 
 
141
    /*
 
142
     * You can assign a raw pointer into a RangedPtr if the raw pointer is
 
143
     * within the range specified at creation.
 
144
     */
 
145
    template <typename U>
 
146
    RangedPtr<T>& operator=(U* p) {
 
147
      *this = create(p);
 
148
      return *this;
 
149
    }
 
150
 
 
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;
 
158
    }
 
159
 
 
160
    RangedPtr<T>& operator++() {
 
161
      return (*this += 1);
 
162
    }
 
163
 
 
164
    RangedPtr<T> operator++(int) {
 
165
      RangedPtr<T> rcp = *this;
 
166
      ++*this;
 
167
      return rcp;
 
168
    }
 
169
 
 
170
    RangedPtr<T>& operator--() {
 
171
      return (*this -= 1);
 
172
    }
 
173
 
 
174
    RangedPtr<T> operator--(int) {
 
175
      RangedPtr<T> rcp = *this;
 
176
      --*this;
 
177
      return rcp;
 
178
    }
 
179
 
 
180
    RangedPtr<T>& operator+=(size_t inc) {
 
181
      *this = *this + inc;
 
182
      return *this;
 
183
    }
 
184
 
 
185
    RangedPtr<T>& operator-=(size_t dec) {
 
186
      *this = *this - dec;
 
187
      return *this;
 
188
    }
 
189
 
 
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);
 
193
    }
 
194
 
 
195
    T& operator*() const {
 
196
      return *ptr;
 
197
    }
 
198
 
 
199
    template <typename U>
 
200
    bool operator==(const RangedPtr<U>& other) const {
 
201
      return ptr == other.ptr;
 
202
    }
 
203
    template <typename U>
 
204
    bool operator!=(const RangedPtr<U>& other) const {
 
205
      return !(*this == other);
 
206
    }
 
207
 
 
208
    template<typename U>
 
209
    bool operator==(const U* u) const {
 
210
      return ptr == u;
 
211
    }
 
212
    template<typename U>
 
213
    bool operator!=(const U* u) const {
 
214
      return !(*this == u);
 
215
    }
 
216
 
 
217
    template <typename U>
 
218
    bool operator<(const RangedPtr<U>& other) const {
 
219
      return ptr < other.ptr;
 
220
    }
 
221
    template <typename U>
 
222
    bool operator<=(const RangedPtr<U>& other) const {
 
223
      return ptr <= other.ptr;
 
224
    }
 
225
 
 
226
    template <typename U>
 
227
    bool operator>(const RangedPtr<U>& other) const {
 
228
      return ptr > other.ptr;
 
229
    }
 
230
    template <typename U>
 
231
    bool operator>=(const RangedPtr<U>& other) const {
 
232
      return ptr >= other.ptr;
 
233
    }
 
234
 
 
235
    size_t operator-(const RangedPtr<T>& other) const {
 
236
      MOZ_ASSERT(ptr >= other.ptr);
 
237
      return PointerRangeSize(other.ptr, ptr);
 
238
    }
 
239
 
 
240
  private:
 
241
    RangedPtr() MOZ_DELETE;
 
242
    T* operator&() MOZ_DELETE;
 
243
    operator T*() const MOZ_DELETE;
 
244
};
 
245
 
 
246
} /* namespace mozilla */
 
247
 
 
248
#endif  /* mozilla_RangedPtr_h_ */