summaryrefslogtreecommitdiffstats
path: root/js/public/GCVector.h
blob: 2668e65b2cf9fdf999c03fea97a94543910700b4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 * vim: set ts=8 sts=4 et sw=4 tw=99:
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef js_GCVector_h
#define js_GCVector_h

#include "mozilla/Vector.h"

#include "js/GCPolicyAPI.h"
#include "js/RootingAPI.h"
#include "js/TracingAPI.h"
#include "js/Vector.h"

namespace JS {

// A GCVector is a Vector with an additional trace method that knows how
// to visit all of the items stored in the Vector. For vectors that contain GC
// things, this is usually more convenient than manually iterating and marking
// the contents.
//
// Most types of GC pointers as keys and values can be traced with no extra
// infrastructure. For structs and non-gc-pointer members, ensure that there is
// a specialization of GCPolicy<T> with an appropriate trace method available
// to handle the custom type. Generic helpers can be found in
// js/public/TracingAPI.h.
//
// Note that although this Vector's trace will deal correctly with moved items,
// it does not itself know when to barrier or trace items. To function properly
// it must either be used with Rooted, or barriered and traced manually.
template <typename T,
          size_t MinInlineCapacity = 0,
          typename AllocPolicy = js::TempAllocPolicy>
class GCVector
{
    mozilla::Vector<T, MinInlineCapacity, AllocPolicy> vector;

  public:
    explicit GCVector(AllocPolicy alloc = AllocPolicy())
      : vector(alloc)
    {}

    GCVector(GCVector&& vec)
      : vector(mozilla::Move(vec.vector))
    {}

    GCVector& operator=(GCVector&& vec) {
        vector = mozilla::Move(vec.vector);
        return *this;
    }

    size_t length() const { return vector.length(); }
    bool empty() const { return vector.empty(); }
    size_t capacity() const { return vector.capacity(); }

    T* begin() { return vector.begin(); }
    const T* begin() const { return vector.begin(); }

    T* end() { return vector.end(); }
    const T* end() const { return vector.end(); }

    T& operator[](size_t i) { return vector[i]; }
    const T& operator[](size_t i) const { return vector[i]; }

    T& back() { return vector.back(); }
    const T& back() const { return vector.back(); }

    bool initCapacity(size_t cap) { return vector.initCapacity(cap); }
    bool reserve(size_t req) { return vector.reserve(req); }
    void shrinkBy(size_t amount) { return vector.shrinkBy(amount); }
    bool growBy(size_t amount) { return vector.growBy(amount); }
    bool resize(size_t newLen) { return vector.resize(newLen); }

    void clear() { return vector.clear(); }

    template<typename U> bool append(U&& item) { return vector.append(mozilla::Forward<U>(item)); }

    template<typename... Args>
    bool
    emplaceBack(Args&&... args) {
        return vector.emplaceBack(mozilla::Forward<Args>(args)...);
    }

    template<typename U>
    void infallibleAppend(U&& aU) {
        return vector.infallibleAppend(mozilla::Forward<U>(aU));
    }
    void infallibleAppendN(const T& aT, size_t aN) {
        return vector.infallibleAppendN(aT, aN);
    }
    template<typename U> void
    infallibleAppend(const U* aBegin, const U* aEnd) {
        return vector.infallibleAppend(aBegin, aEnd);
    }
    template<typename U> void infallibleAppend(const U* aBegin, size_t aLength) {
        return vector.infallibleAppend(aBegin, aLength);
    }

    template<typename U, size_t O, class BP>
    bool appendAll(const mozilla::Vector<U, O, BP>& aU) { return vector.appendAll(aU); }
    template<typename U, size_t O, class BP>
    bool appendAll(const GCVector<U, O, BP>& aU) { return vector.append(aU.begin(), aU.length()); }

    bool appendN(const T& val, size_t count) { return vector.appendN(val, count); }

    template<typename U> bool append(const U* aBegin, const U* aEnd) {
        return vector.append(aBegin, aEnd);
    }
    template<typename U> bool append(const U* aBegin, size_t aLength) {
        return vector.append(aBegin, aLength);
    }

    void popBack() { return vector.popBack(); }
    T popCopy() { return vector.popCopy(); }

    size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
        return vector.sizeOfExcludingThis(mallocSizeOf);
    }

    size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
        return vector.sizeOfIncludingThis(mallocSizeOf);
    }

    static void trace(GCVector* vec, JSTracer* trc) { vec->trace(trc); }

    void trace(JSTracer* trc) {
        for (auto& elem : vector)
            GCPolicy<T>::trace(trc, &elem, "vector element");
    }
};

} // namespace JS

namespace js {

template <typename Outer, typename T, size_t Capacity, typename AllocPolicy>
class GCVectorOperations
{
    using Vec = JS::GCVector<T, Capacity, AllocPolicy>;
    const Vec& vec() const { return static_cast<const Outer*>(this)->get(); }

  public:
    const AllocPolicy& allocPolicy() const { return vec().allocPolicy(); }
    size_t length() const { return vec().length(); }
    bool empty() const { return vec().empty(); }
    size_t capacity() const { return vec().capacity(); }
    const T* begin() const { return vec().begin(); }
    const T* end() const { return vec().end(); }
    const T& back() const { return vec().back(); }

    JS::Handle<T> operator[](size_t aIndex) const {
        return JS::Handle<T>::fromMarkedLocation(&vec().operator[](aIndex));
    }
};

template <typename Outer, typename T, size_t Capacity, typename AllocPolicy>
class MutableGCVectorOperations
  : public GCVectorOperations<Outer, T, Capacity, AllocPolicy>
{
    using Vec = JS::GCVector<T, Capacity, AllocPolicy>;
    const Vec& vec() const { return static_cast<const Outer*>(this)->get(); }
    Vec& vec() { return static_cast<Outer*>(this)->get(); }

  public:
    const AllocPolicy& allocPolicy() const { return vec().allocPolicy(); }
    AllocPolicy& allocPolicy() { return vec().allocPolicy(); }
    const T* begin() const { return vec().begin(); }
    T* begin() { return vec().begin(); }
    const T* end() const { return vec().end(); }
    T* end() { return vec().end(); }
    const T& back() const { return vec().back(); }
    T& back() { return vec().back(); }

    JS::Handle<T> operator[](size_t aIndex) const {
        return JS::Handle<T>::fromMarkedLocation(&vec().operator[](aIndex));
    }
    JS::MutableHandle<T> operator[](size_t aIndex) {
        return JS::MutableHandle<T>::fromMarkedLocation(&vec().operator[](aIndex));
    }

    bool initCapacity(size_t aRequest) { return vec().initCapacity(aRequest); }
    bool reserve(size_t aRequest) { return vec().reserve(aRequest); }
    void shrinkBy(size_t aIncr) { vec().shrinkBy(aIncr); }
    bool growBy(size_t aIncr) { return vec().growBy(aIncr); }
    bool resize(size_t aNewLength) { return vec().resize(aNewLength); }
    bool growByUninitialized(size_t aIncr) { return vec().growByUninitialized(aIncr); }
    void infallibleGrowByUninitialized(size_t aIncr) { vec().infallibleGrowByUninitialized(aIncr); }
    bool resizeUninitialized(size_t aNewLength) { return vec().resizeUninitialized(aNewLength); }
    void clear() { vec().clear(); }
    void clearAndFree() { vec().clearAndFree(); }
    template<typename U> bool append(U&& aU) { return vec().append(mozilla::Forward<U>(aU)); }
    template<typename... Args> bool emplaceBack(Args&&... aArgs) {
        return vec().emplaceBack(mozilla::Forward<Args...>(aArgs...));
    }
    template<typename U, size_t O, class BP>
    bool appendAll(const mozilla::Vector<U, O, BP>& aU) { return vec().appendAll(aU); }
    template<typename U, size_t O, class BP>
    bool appendAll(const JS::GCVector<U, O, BP>& aU) { return vec().appendAll(aU); }
    bool appendN(const T& aT, size_t aN) { return vec().appendN(aT, aN); }
    template<typename U> bool append(const U* aBegin, const U* aEnd) {
        return vec().append(aBegin, aEnd);
    }
    template<typename U> bool append(const U* aBegin, size_t aLength) {
        return vec().append(aBegin, aLength);
    }
    template<typename U> void infallibleAppend(U&& aU) {
        vec().infallibleAppend(mozilla::Forward<U>(aU));
    }
    void infallibleAppendN(const T& aT, size_t aN) { vec().infallibleAppendN(aT, aN); }
    template<typename U> void infallibleAppend(const U* aBegin, const U* aEnd) {
        vec().infallibleAppend(aBegin, aEnd);
    }
    template<typename U> void infallibleAppend(const U* aBegin, size_t aLength) {
        vec().infallibleAppend(aBegin, aLength);
    }
    void popBack() { vec().popBack(); }
    T popCopy() { return vec().popCopy(); }
    template<typename U> T* insert(T* aP, U&& aVal) {
        return vec().insert(aP, mozilla::Forward<U>(aVal));
    }
    void erase(T* aT) { vec().erase(aT); }
    void erase(T* aBegin, T* aEnd) { vec().erase(aBegin, aEnd); }
};

template <typename T, size_t N, typename AP>
class RootedBase<JS::GCVector<T,N,AP>>
  : public MutableGCVectorOperations<JS::Rooted<JS::GCVector<T,N,AP>>, T,N,AP>
{};

template <typename T, size_t N, typename AP>
class MutableHandleBase<JS::GCVector<T,N,AP>>
  : public MutableGCVectorOperations<JS::MutableHandle<JS::GCVector<T,N,AP>>, T,N,AP>
{};

template <typename T, size_t N, typename AP>
class HandleBase<JS::GCVector<T,N,AP>>
  : public GCVectorOperations<JS::Handle<JS::GCVector<T,N,AP>>, T,N,AP>
{};

template <typename T, size_t N, typename AP>
class PersistentRootedBase<JS::GCVector<T,N,AP>>
  : public MutableGCVectorOperations<JS::PersistentRooted<JS::GCVector<T,N,AP>>, T,N,AP>
{};

} // namespace js

#endif // js_GCVector_h