Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/xpcom/ds/nsArrayEnumerator.cpp
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
#include "mozilla/Attributes.h"
8
9
#include "nsArrayEnumerator.h"
10
11
#include "nsIArray.h"
12
#include "nsSimpleEnumerator.h"
13
14
#include "nsCOMArray.h"
15
#include "nsCOMPtr.h"
16
#include "mozilla/OperatorNewExtensions.h"
17
#include "mozilla/RefPtr.h"
18
19
class nsSimpleArrayEnumerator final : public nsSimpleEnumerator
20
{
21
public:
22
  // nsISimpleEnumerator interface
23
  NS_DECL_NSISIMPLEENUMERATOR
24
25
  // nsSimpleArrayEnumerator methods
26
  explicit nsSimpleArrayEnumerator(nsIArray* aValueArray, const nsID& aEntryIID)
27
    : mValueArray(aValueArray)
28
    , mEntryIID(aEntryIID)
29
    , mIndex(0)
30
0
  {
31
0
  }
32
33
0
  const nsID& DefaultInterface() override { return mEntryIID; }
34
35
private:
36
0
  ~nsSimpleArrayEnumerator() override = default;
37
38
protected:
39
  nsCOMPtr<nsIArray> mValueArray;
40
  const nsID mEntryIID;
41
  uint32_t mIndex;
42
};
43
44
NS_IMETHODIMP
45
nsSimpleArrayEnumerator::HasMoreElements(bool* aResult)
46
0
{
47
0
  MOZ_ASSERT(aResult != 0, "null ptr");
48
0
  if (!aResult) {
49
0
    return NS_ERROR_NULL_POINTER;
50
0
  }
51
0
52
0
  if (!mValueArray) {
53
0
    *aResult = false;
54
0
    return NS_OK;
55
0
  }
56
0
57
0
  uint32_t cnt;
58
0
  nsresult rv = mValueArray->GetLength(&cnt);
59
0
  if (NS_FAILED(rv)) {
60
0
    return rv;
61
0
  }
62
0
  *aResult = (mIndex < cnt);
63
0
  return NS_OK;
64
0
}
65
66
NS_IMETHODIMP
67
nsSimpleArrayEnumerator::GetNext(nsISupports** aResult)
68
0
{
69
0
  MOZ_ASSERT(aResult != 0, "null ptr");
70
0
  if (!aResult) {
71
0
    return NS_ERROR_NULL_POINTER;
72
0
  }
73
0
74
0
  if (!mValueArray) {
75
0
    *aResult = nullptr;
76
0
    return NS_OK;
77
0
  }
78
0
79
0
  uint32_t cnt;
80
0
  nsresult rv = mValueArray->GetLength(&cnt);
81
0
  if (NS_FAILED(rv)) {
82
0
    return rv;
83
0
  }
84
0
  if (mIndex >= cnt) {
85
0
    return NS_ERROR_UNEXPECTED;
86
0
  }
87
0
88
0
  return mValueArray->QueryElementAt(mIndex++, NS_GET_IID(nsISupports),
89
0
                                     (void**)aResult);
90
0
}
91
92
nsresult
93
NS_NewArrayEnumerator(nsISimpleEnumerator** aResult, nsIArray* aArray,
94
                      const nsID& aEntryIID)
95
0
{
96
0
  RefPtr<nsSimpleArrayEnumerator> enumer = new nsSimpleArrayEnumerator(aArray, aEntryIID);
97
0
  enumer.forget(aResult);
98
0
  return NS_OK;
99
0
}
100
101
////////////////////////////////////////////////////////////////////////////////
102
103
// enumerator implementation for nsCOMArray
104
// creates a snapshot of the array in question
105
// you MUST use NS_NewArrayEnumerator to create this, so that
106
// allocation is done correctly
107
class nsCOMArrayEnumerator final : public nsSimpleEnumerator
108
{
109
public:
110
  // nsISimpleEnumerator interface
111
  NS_DECL_NSISIMPLEENUMERATOR
112
113
  // Use this instead of `new`.
114
  static nsCOMArrayEnumerator* Allocate(const nsCOMArray_base& aArray, const nsID& aEntryIID);
115
116
  // specialized operator to make sure we make room for mValues
117
3
  void operator delete(void* aPtr) { free(aPtr); }
118
119
0
  const nsID& DefaultInterface() override { return mEntryIID; }
120
121
private:
122
  // nsSimpleArrayEnumerator methods
123
  explicit nsCOMArrayEnumerator(const nsID& aEntryIID)
124
    : mIndex(0)
125
    , mArraySize(0)
126
    , mEntryIID(aEntryIID)
127
3
  {
128
3
    mValueArray[0] = nullptr;
129
3
  }
130
131
  ~nsCOMArrayEnumerator(void) override;
132
133
protected:
134
  uint32_t mIndex;            // current position
135
  uint32_t mArraySize;        // size of the array
136
137
  const nsID& mEntryIID;
138
139
  // this is actually bigger
140
  nsISupports* mValueArray[1];
141
};
142
143
nsCOMArrayEnumerator::~nsCOMArrayEnumerator()
144
3
{
145
3
  // only release the entries that we haven't visited yet
146
3
  for (; mIndex < mArraySize; ++mIndex) {
147
0
    NS_IF_RELEASE(mValueArray[mIndex]);
148
0
  }
149
3
}
150
151
NS_IMETHODIMP
152
nsCOMArrayEnumerator::HasMoreElements(bool* aResult)
153
0
{
154
0
  MOZ_ASSERT(aResult != 0, "null ptr");
155
0
  if (!aResult) {
156
0
    return NS_ERROR_NULL_POINTER;
157
0
  }
158
0
159
0
  *aResult = (mIndex < mArraySize);
160
0
  return NS_OK;
161
0
}
162
163
NS_IMETHODIMP
164
nsCOMArrayEnumerator::GetNext(nsISupports** aResult)
165
6
{
166
6
  MOZ_ASSERT(aResult != 0, "null ptr");
167
6
  if (!aResult) {
168
0
    return NS_ERROR_NULL_POINTER;
169
0
  }
170
6
171
6
  if (mIndex >= mArraySize) {
172
3
    return NS_ERROR_UNEXPECTED;
173
3
  }
174
3
175
3
  // pass the ownership of the reference to the caller. Since
176
3
  // we AddRef'ed during creation of |this|, there is no need
177
3
  // to AddRef here
178
3
  *aResult = mValueArray[mIndex++];
179
3
180
3
  // this really isn't necessary. just pretend this happens, since
181
3
  // we'll never visit this value again!
182
3
  // mValueArray[(mIndex-1)] = nullptr;
183
3
184
3
  return NS_OK;
185
3
}
186
187
nsCOMArrayEnumerator*
188
nsCOMArrayEnumerator::Allocate(const nsCOMArray_base& aArray, const nsID& aEntryIID)
189
3
{
190
3
  // create enough space such that mValueArray points to a large
191
3
  // enough value. Note that the initial value of aSize gives us
192
3
  // space for mValueArray[0], so we must subtract
193
3
  size_t size = sizeof(nsCOMArrayEnumerator);
194
3
  uint32_t count;
195
3
  if (aArray.Count() > 0) {
196
3
    count = static_cast<uint32_t>(aArray.Count());
197
3
    size += (count - 1) * sizeof(aArray[0]);
198
3
  } else {
199
0
    count = 0;
200
0
  }
201
3
202
3
  // Allocate a buffer large enough to contain our object and its array.
203
3
  void* mem = moz_xmalloc(size);
204
3
  auto result = new (mozilla::KnownNotNull, mem) nsCOMArrayEnumerator(aEntryIID);
205
3
206
3
  result->mArraySize = count;
207
3
208
3
  // now need to copy over the values, and addref each one
209
3
  // now this might seem like a lot of work, but we're actually just
210
3
  // doing all our AddRef's ahead of time since GetNext() doesn't
211
3
  // need to AddRef() on the way out
212
6
  for (uint32_t i = 0; i < count; ++i) {
213
3
    result->mValueArray[i] = aArray[i];
214
3
    NS_IF_ADDREF(result->mValueArray[i]);
215
3
  }
216
3
217
3
  return result;
218
3
}
219
220
nsresult
221
NS_NewArrayEnumerator(nsISimpleEnumerator** aResult,
222
                      const nsCOMArray_base& aArray,
223
                      const nsID& aEntryIID)
224
3
{
225
3
  RefPtr<nsCOMArrayEnumerator> enumerator = nsCOMArrayEnumerator::Allocate(aArray, aEntryIID);
226
3
  enumerator.forget(aResult);
227
3
  return NS_OK;
228
3
}