Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/xpcom/ds/nsDeque.h
Line
Count
Source (jump to first uncovered line)
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/. */
6
7
/**
8
 * MODULE NOTES:
9
 *
10
 * The Deque is a very small, very efficient container object
11
 * than can hold items of type void*, offering the following features:
12
 * - Its interface supports pushing, popping, and peeking of items at the back
13
 *   or front, and retrieval from any position.
14
 * - It can iterate over items via a ForEach method, range-for, or an iterator
15
 *   class.
16
 * - When full, it can efficiently resize dynamically.
17
 *
18
 * NOTE: The only bit of trickery here is that this deque is
19
 * built upon a ring-buffer. Like all ring buffers, the first
20
 * item may not be at index[0]. The mOrigin member determines
21
 * where the first child is. This point is quietly hidden from
22
 * customers of this class.
23
 */
24
25
#ifndef _NSDEQUE
26
#define _NSDEQUE
27
28
#include "nscore.h"
29
#include "nsDebug.h"
30
#include "mozilla/Attributes.h"
31
#include "mozilla/fallible.h"
32
#include "mozilla/MemoryReporting.h"
33
34
/**
35
 * The nsDequeFunctor class is used when you want to create
36
 * callbacks between the deque and your generic code.
37
 * Use these objects in a call to ForEach(), and as custom deallocators.
38
 */
39
class nsDequeFunctor
40
{
41
public:
42
  virtual void operator()(void* aObject) = 0;
43
  virtual ~nsDequeFunctor() {}
44
};
45
46
/******************************************************
47
 * Here comes the nsDeque class itself...
48
 ******************************************************/
49
50
/**
51
 * The deque (double-ended queue) class is a common container type,
52
 * whose behavior mimics a line in your favorite checkout stand.
53
 * Classic CS describes the common behavior of a queue as FIFO.
54
 * A deque allows insertion and removal at both ends of
55
 * the container.
56
 *
57
 * The deque stores pointers to items.
58
 */
59
class nsDeque
60
{
61
  typedef mozilla::fallible_t fallible_t;
62
public:
63
  /**
64
   * Constructs an empty deque.
65
   *
66
   * @param   aDeallocator Optional deallocator functor that will be called from
67
   *                       Erase() and the destructor on any remaining item.
68
   *                       The deallocator is owned by the deque and will be
69
   *                       deleted at destruction time.
70
   */
71
  explicit nsDeque(nsDequeFunctor* aDeallocator = nullptr);
72
73
  /**
74
   * Deque destructor. Erases all items, deletes the deallocator.
75
   */
76
  ~nsDeque();
77
78
  /**
79
   * Returns the number of items currently stored in
80
   * this deque.
81
   *
82
   * @return  number of items currently in the deque
83
   */
84
0
  inline size_t GetSize() const { return mSize; }
85
86
  /**
87
   * Appends new member at the end of the deque.
88
   *
89
   * @param   aItem item to store in deque
90
   */
91
  void Push(void* aItem)
92
  {
93
    if (!Push(aItem, mozilla::fallible)) {
94
      NS_ABORT_OOM(mSize * sizeof(void*));
95
    }
96
  }
97
98
  /**
99
   * Appends new member at the end of the deque.
100
   *
101
   * @param   aItem item to store in deque
102
   * @return  true if succeeded, false if failed to resize deque as needed
103
   */
104
  MOZ_MUST_USE bool Push(void* aItem, const fallible_t&);
105
106
  /**
107
   * Inserts new member at the front of the deque.
108
   *
109
   * @param   aItem item to store in deque
110
   */
111
  void PushFront(void* aItem)
112
  {
113
    if (!PushFront(aItem, mozilla::fallible)) {
114
      NS_ABORT_OOM(mSize * sizeof(void*));
115
    }
116
  }
117
118
  /**
119
   * Inserts new member at the front of the deque.
120
   *
121
   * @param   aItem item to store in deque
122
   * @return  true if succeeded, false if failed to resize deque as needed
123
   */
124
  MOZ_MUST_USE bool PushFront(void* aItem, const fallible_t&);
125
126
  /**
127
   * Remove and return the last item in the container.
128
   *
129
   * @return  the item that was the last item in container
130
   */
131
  void* Pop();
132
133
  /**
134
   * Remove and return the first item in the container.
135
   *
136
   * @return  the item that was first item in container
137
   */
138
  void* PopFront();
139
140
  /**
141
   * Retrieve the last item without removing it.
142
   *
143
   * @return  the last item in container
144
   */
145
  void* Peek() const;
146
147
  /**
148
   * Retrieve the first item without removing it.
149
   *
150
   * @return  the first item in container
151
   */
152
  void* PeekFront() const;
153
154
  /**
155
   * Retrieve a member from the deque without removing it.
156
   *
157
   * @param   index of desired item
158
   * @return  item in list, or nullptr if index is outside the deque
159
   */
160
  void* ObjectAt(size_t aIndex) const;
161
162
  /**
163
   * Remove and delete all items from container.
164
   * Deletes are handled by the deallocator nsDequeFunctor
165
   * which is specified at deque construction.
166
   */
167
  void Erase();
168
169
  /**
170
   * Call this method when you want to iterate through all
171
   * items in the container, passing a functor along
172
   * to call your code.
173
   * If the deque is modified during ForEach, iteration will continue based on
174
   * item indices; meaning that front operations may effectively skip over
175
   * items or visit some items multiple times.
176
   *
177
   * @param   aFunctor object to call for each member
178
   */
179
  void ForEach(nsDequeFunctor& aFunctor) const;
180
181
  // This iterator assumes that the deque itself is const, i.e., it cannot be
182
  // modified while the iterator is used.
183
  // Also it is a 'const' iterator in that it provides copies of the deque's
184
  // elements, and therefore it is not possible to modify the deque's contents
185
  // by assigning to a dereference of this iterator.
186
  class ConstDequeIterator
187
  {
188
  public:
189
    ConstDequeIterator(const nsDeque& aDeque, size_t aIndex)
190
      : mDeque(aDeque)
191
      , mIndex(aIndex)
192
    {
193
    }
194
    ConstDequeIterator& operator++()
195
    {
196
      ++mIndex;
197
      return *this;
198
    }
199
    bool operator==(const ConstDequeIterator& aOther) const
200
0
    {
201
0
      return mIndex == aOther.mIndex;
202
0
    }
203
    bool operator!=(const ConstDequeIterator& aOther) const
204
    {
205
      return mIndex != aOther.mIndex;
206
    }
207
    void* operator*() const
208
    {
209
      // Don't allow out-of-deque dereferences.
210
      MOZ_RELEASE_ASSERT(mIndex < mDeque.GetSize());
211
      return mDeque.ObjectAt(mIndex);
212
    }
213
  private:
214
    const nsDeque& mDeque;
215
    size_t mIndex;
216
  };
217
  // If this deque is const, we can provide ConstDequeIterator's.
218
  ConstDequeIterator begin() const
219
  {
220
    return ConstDequeIterator(*this, 0);
221
  }
222
  ConstDequeIterator end() const
223
  {
224
    return ConstDequeIterator(*this, mSize);
225
  }
226
227
  // It is a 'const' iterator in that it provides copies of the deque's
228
  // elements, and therefore it is not possible to modify the deque's contents
229
  // by assigning to a dereference of this iterator.
230
  // If the deque is modified in other ways, this iterator will stay at the same
231
  // index, and will handle past-the-end comparisons, but not dereferencing.
232
  class ConstIterator
233
  {
234
  public:
235
    // Special index for the end iterator, to track the possibly-shifting
236
    // deque size.
237
    static const size_t EndIteratorIndex = size_t(-1);
238
239
    ConstIterator(const nsDeque& aDeque, size_t aIndex)
240
      : mDeque(aDeque)
241
      , mIndex(aIndex)
242
    {
243
    }
244
    ConstIterator& operator++()
245
    {
246
      // End-iterator shouldn't be modified.
247
      MOZ_ASSERT(mIndex != EndIteratorIndex);
248
      ++mIndex;
249
      return *this;
250
    }
251
    bool operator==(const ConstIterator& aOther) const
252
0
    {
253
0
      return EffectiveIndex() == aOther.EffectiveIndex();
254
0
    }
255
    bool operator!=(const ConstIterator& aOther) const
256
    {
257
      return EffectiveIndex() != aOther.EffectiveIndex();
258
    }
259
    void* operator*() const
260
    {
261
      // Don't allow out-of-deque dereferences.
262
      MOZ_RELEASE_ASSERT(mIndex < mDeque.GetSize());
263
      return mDeque.ObjectAt(mIndex);
264
    }
265
  private:
266
    // 0 <= index < deque.GetSize() inside the deque, deque.GetSize() otherwise.
267
    // Only used when comparing indices, not to actually access items.
268
    size_t EffectiveIndex() const
269
    {
270
      return (mIndex < mDeque.GetSize()) ? mIndex : mDeque.GetSize();
271
    }
272
273
    const nsDeque& mDeque;
274
    size_t mIndex; // May point outside the deque!
275
  };
276
  // If this deque is *not* const, we provide ConstIterator's that can handle
277
  // deque size changes.
278
  ConstIterator begin()
279
  {
280
    return ConstIterator(*this, 0);
281
  }
282
  ConstIterator end()
283
  {
284
    return ConstIterator(*this, ConstIterator::EndIteratorIndex);
285
  }
286
287
  size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
288
  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
289
290
protected:
291
  size_t         mSize;
292
  size_t         mCapacity;
293
  size_t         mOrigin;
294
  nsDequeFunctor* mDeallocator;
295
  void*           mBuffer[8];
296
  void**          mData;
297
298
private:
299
300
  /**
301
   * Copy constructor (deleted)
302
   *
303
   * @param aOther another deque
304
   */
305
  nsDeque(const nsDeque& aOther) = delete;
306
307
  /**
308
   * Deque assignment operator (deleted)
309
   *
310
   * @param aOther another deque
311
   * @return *this
312
   */
313
  nsDeque& operator=(const nsDeque& aOther) = delete;
314
315
  bool GrowCapacity();
316
  void SetDeallocator(nsDequeFunctor* aDeallocator);
317
318
  /**
319
   * Remove all items from container without destroying them.
320
   */
321
  void Empty();
322
};
323
#endif