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/. */
7 #include "mozilla/Attributes.h"
9 #include "nsArrayEnumerator.h"
12 #include "nsSimpleEnumerator.h"
14 #include "nsCOMArray.h"
16 #include "mozilla/OperatorNewExtensions.h"
17 #include "mozilla/RefPtr.h"
19 class nsSimpleArrayEnumerator final
: public nsSimpleEnumerator
{
21 // nsISimpleEnumerator interface
22 NS_DECL_NSISIMPLEENUMERATOR
24 // nsSimpleArrayEnumerator methods
25 explicit nsSimpleArrayEnumerator(nsIArray
* aValueArray
, const nsID
& aEntryIID
)
26 : mValueArray(aValueArray
), mEntryIID(aEntryIID
), mIndex(0) {}
28 const nsID
& DefaultInterface() override
{ return mEntryIID
; }
31 ~nsSimpleArrayEnumerator() override
= default;
34 nsCOMPtr
<nsIArray
> mValueArray
;
40 nsSimpleArrayEnumerator::HasMoreElements(bool* aResult
) {
41 MOZ_ASSERT(aResult
!= 0, "null ptr");
43 return NS_ERROR_NULL_POINTER
;
52 nsresult rv
= mValueArray
->GetLength(&cnt
);
56 *aResult
= (mIndex
< cnt
);
61 nsSimpleArrayEnumerator::GetNext(nsISupports
** aResult
) {
62 MOZ_ASSERT(aResult
!= 0, "null ptr");
64 return NS_ERROR_NULL_POINTER
;
73 nsresult rv
= mValueArray
->GetLength(&cnt
);
78 return NS_ERROR_UNEXPECTED
;
81 return mValueArray
->QueryElementAt(mIndex
++, NS_GET_IID(nsISupports
),
85 nsresult
NS_NewArrayEnumerator(nsISimpleEnumerator
** aResult
, nsIArray
* aArray
,
86 const nsID
& aEntryIID
) {
87 RefPtr
<nsSimpleArrayEnumerator
> enumer
=
88 new nsSimpleArrayEnumerator(aArray
, aEntryIID
);
89 enumer
.forget(aResult
);
93 ////////////////////////////////////////////////////////////////////////////////
95 // enumerator implementation for nsCOMArray
96 // creates a snapshot of the array in question
97 // you MUST use NS_NewArrayEnumerator to create this, so that
98 // allocation is done correctly
99 class nsCOMArrayEnumerator final
: public nsSimpleEnumerator
{
101 // nsISimpleEnumerator interface
102 NS_DECL_NSISIMPLEENUMERATOR
104 // Use this instead of `new`.
105 static nsCOMArrayEnumerator
* Allocate(const nsCOMArray_base
& aArray
,
106 const nsID
& aEntryIID
);
108 // specialized operator to make sure we make room for mValues
109 void operator delete(void* aPtr
) { free(aPtr
); }
111 const nsID
& DefaultInterface() override
{ return mEntryIID
; }
114 // nsSimpleArrayEnumerator methods
115 explicit nsCOMArrayEnumerator(const nsID
& aEntryIID
)
116 : mIndex(0), mArraySize(0), mEntryIID(aEntryIID
) {
117 mValueArray
[0] = nullptr;
120 ~nsCOMArrayEnumerator(void) override
;
123 uint32_t mIndex
; // current position
124 uint32_t mArraySize
; // size of the array
126 const nsID
& mEntryIID
;
128 // this is actually bigger
129 nsISupports
* mValueArray
[1];
132 nsCOMArrayEnumerator::~nsCOMArrayEnumerator() {
133 // only release the entries that we haven't visited yet
134 for (; mIndex
< mArraySize
; ++mIndex
) {
135 NS_IF_RELEASE(mValueArray
[mIndex
]);
140 nsCOMArrayEnumerator::HasMoreElements(bool* aResult
) {
141 MOZ_ASSERT(aResult
!= 0, "null ptr");
143 return NS_ERROR_NULL_POINTER
;
146 *aResult
= (mIndex
< mArraySize
);
151 nsCOMArrayEnumerator::GetNext(nsISupports
** aResult
) {
152 MOZ_ASSERT(aResult
!= 0, "null ptr");
154 return NS_ERROR_NULL_POINTER
;
157 if (mIndex
>= mArraySize
) {
158 return NS_ERROR_UNEXPECTED
;
161 // pass the ownership of the reference to the caller. Since
162 // we AddRef'ed during creation of |this|, there is no need
164 *aResult
= mValueArray
[mIndex
++];
166 // this really isn't necessary. just pretend this happens, since
167 // we'll never visit this value again!
168 // mValueArray[(mIndex-1)] = nullptr;
173 nsCOMArrayEnumerator
* nsCOMArrayEnumerator::Allocate(
174 const nsCOMArray_base
& aArray
, const nsID
& aEntryIID
) {
175 // create enough space such that mValueArray points to a large
176 // enough value. Note that the initial value of aSize gives us
177 // space for mValueArray[0], so we must subtract
178 size_t size
= sizeof(nsCOMArrayEnumerator
);
180 if (aArray
.Count() > 0) {
181 count
= static_cast<uint32_t>(aArray
.Count());
182 size
+= (count
- 1) * sizeof(aArray
[0]);
187 // Allocate a buffer large enough to contain our object and its array.
188 void* mem
= moz_xmalloc(size
);
190 new (mozilla::KnownNotNull
, mem
) nsCOMArrayEnumerator(aEntryIID
);
192 result
->mArraySize
= count
;
194 // now need to copy over the values, and addref each one
195 // now this might seem like a lot of work, but we're actually just
196 // doing all our AddRef's ahead of time since GetNext() doesn't
197 // need to AddRef() on the way out
198 for (uint32_t i
= 0; i
< count
; ++i
) {
199 result
->mValueArray
[i
] = aArray
[i
];
200 NS_IF_ADDREF(result
->mValueArray
[i
]);
206 nsresult
NS_NewArrayEnumerator(nsISimpleEnumerator
** aResult
,
207 const nsCOMArray_base
& aArray
,
208 const nsID
& aEntryIID
) {
209 RefPtr
<nsCOMArrayEnumerator
> enumerator
=
210 nsCOMArrayEnumerator::Allocate(aArray
, aEntryIID
);
211 enumerator
.forget(aResult
);