1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; c-file-offsets: ((substatement-open . 0)) -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 : #ifndef nsVoidArray_h___
38 : #define nsVoidArray_h___
39 :
40 : //#define DEBUG_VOIDARRAY 1
41 :
42 : #include "nsDebug.h"
43 :
44 : // Comparator callback function for sorting array values.
45 : typedef int (* nsVoidArrayComparatorFunc)
46 : (const void* aElement1, const void* aElement2, void* aData);
47 :
48 : // Enumerator callback function. Return false to stop
49 : typedef bool (* nsVoidArrayEnumFunc)(void* aElement, void *aData);
50 : typedef bool (* nsVoidArrayEnumFuncConst)(const void* aElement, void *aData);
51 :
52 : // SizeOfExcludingThis callback function.
53 : typedef size_t (* nsVoidArraySizeOfElementIncludingThisFunc)(const void* aElement,
54 : nsMallocSizeOfFun aMallocSizeOf,
55 : void *aData);
56 :
57 : /// A basic zero-based array of void*'s that manages its own memory
58 : class NS_COM_GLUE nsVoidArray {
59 : public:
60 : nsVoidArray();
61 : nsVoidArray(PRInt32 aCount); // initial count of aCount elements set to nsnull
62 : ~nsVoidArray();
63 :
64 : nsVoidArray& operator=(const nsVoidArray& other);
65 :
66 0 : inline PRInt32 Count() const {
67 0 : return mImpl ? mImpl->mCount : 0;
68 : }
69 : // If the array grows, the newly created entries will all be null
70 : bool SetCount(PRInt32 aNewCount);
71 : // returns the max number that can be held without allocating
72 1590914 : inline PRInt32 GetArraySize() const {
73 1590914 : return mImpl ? (PRInt32(mImpl->mBits) & kArraySizeMask) : 0;
74 : }
75 :
76 1390 : void* FastElementAt(PRInt32 aIndex) const
77 : {
78 1390 : NS_ASSERTION(0 <= aIndex && aIndex < Count(), "nsVoidArray::FastElementAt: index out of range");
79 1390 : return mImpl->mArray[aIndex];
80 : }
81 :
82 : // This both asserts and bounds-checks, because (1) we don't want
83 : // people to write bad code, but (2) we don't want to change it to
84 : // crashing for backwards compatibility. See bug 96108.
85 0 : void* ElementAt(PRInt32 aIndex) const
86 : {
87 0 : NS_ASSERTION(0 <= aIndex && aIndex < Count(), "nsVoidArray::ElementAt: index out of range");
88 0 : return SafeElementAt(aIndex);
89 : }
90 :
91 : // bounds-checked version
92 0 : void* SafeElementAt(PRInt32 aIndex) const
93 : {
94 0 : if (PRUint32(aIndex) >= PRUint32(Count())) // handles aIndex < 0 too
95 : {
96 0 : return nsnull;
97 : }
98 : // The bounds check ensures mImpl is non-null.
99 0 : return mImpl->mArray[aIndex];
100 : }
101 :
102 : void* operator[](PRInt32 aIndex) const { return ElementAt(aIndex); }
103 :
104 : PRInt32 IndexOf(void* aPossibleElement) const;
105 :
106 : bool InsertElementAt(void* aElement, PRInt32 aIndex);
107 : bool InsertElementsAt(const nsVoidArray &other, PRInt32 aIndex);
108 :
109 : bool ReplaceElementAt(void* aElement, PRInt32 aIndex);
110 :
111 : // useful for doing LRU arrays, sorting, etc
112 : bool MoveElement(PRInt32 aFrom, PRInt32 aTo);
113 :
114 0 : bool AppendElement(void* aElement) {
115 0 : return InsertElementAt(aElement, Count());
116 : }
117 :
118 : bool AppendElements(nsVoidArray& aElements) {
119 : return InsertElementsAt(aElements, Count());
120 : }
121 :
122 : bool RemoveElement(void* aElement);
123 : bool RemoveElementsAt(PRInt32 aIndex, PRInt32 aCount);
124 2 : bool RemoveElementAt(PRInt32 aIndex) { return RemoveElementsAt(aIndex,1); }
125 :
126 : void Clear();
127 :
128 : bool SizeTo(PRInt32 aMin);
129 : // Subtly different - Compact() tries to be smart about whether we
130 : // should reallocate the array; SizeTo() always reallocates.
131 : void Compact();
132 :
133 : void Sort(nsVoidArrayComparatorFunc aFunc, void* aData);
134 :
135 : bool EnumerateForwards(nsVoidArrayEnumFunc aFunc, void* aData);
136 : bool EnumerateForwards(nsVoidArrayEnumFuncConst aFunc, void* aData) const;
137 : bool EnumerateBackwards(nsVoidArrayEnumFunc aFunc, void* aData);
138 :
139 : // Measures the size of the array's element storage, and if
140 : // |aSizeOfElementIncludingThis| is non-NULL, measures the size of things
141 : // pointed to by elements.
142 : size_t SizeOfExcludingThis(
143 : nsVoidArraySizeOfElementIncludingThisFunc aSizeOfElementIncludingThis,
144 : nsMallocSizeOfFun aMallocSizeOf, void* aData = NULL) const;
145 :
146 : protected:
147 : bool GrowArrayBy(PRInt32 aGrowBy);
148 :
149 : struct Impl {
150 : /**
151 : * Packed bits. The low 30 bits are the array's size.
152 : * The two highest bits indicate whether or not we "own" mImpl and
153 : * must free() it when destroyed, and whether we have a preallocated
154 : * nsAutoVoidArray buffer.
155 : */
156 : PRUint32 mBits;
157 :
158 : /**
159 : * The number of elements in the array
160 : */
161 : PRInt32 mCount;
162 :
163 : /**
164 : * Array data, padded out to the actual size of the array.
165 : */
166 : void* mArray[1];
167 : };
168 :
169 : Impl* mImpl;
170 : #if DEBUG_VOIDARRAY
171 : PRInt32 mMaxCount;
172 : PRInt32 mMaxSize;
173 : bool mIsAuto;
174 : #endif
175 :
176 : enum {
177 : kArrayOwnerMask = 1 << 31,
178 : kArrayHasAutoBufferMask = 1 << 30,
179 : kArraySizeMask = ~(kArrayOwnerMask | kArrayHasAutoBufferMask)
180 : };
181 : enum { kAutoBufSize = 8 };
182 :
183 :
184 : // bit twiddlers
185 : void SetArray(Impl *newImpl, PRInt32 aSize, PRInt32 aCount, bool aOwner,
186 : bool aHasAuto);
187 979979 : inline bool IsArrayOwner() const {
188 979979 : return mImpl && (mImpl->mBits & kArrayOwnerMask);
189 : }
190 705001 : inline bool HasAutoBuffer() const {
191 705001 : return mImpl && (mImpl->mBits & kArrayHasAutoBufferMask);
192 : }
193 :
194 : private:
195 : /// Copy constructors are not allowed
196 : nsVoidArray(const nsVoidArray& other);
197 : };
198 :
199 :
200 : // A zero-based array with a bit of automatic internal storage
201 293785 : class NS_COM_GLUE nsAutoVoidArray : public nsVoidArray {
202 : public:
203 : nsAutoVoidArray();
204 :
205 293786 : void ResetToAutoBuffer()
206 : {
207 : SetArray(reinterpret_cast<Impl*>(mAutoBuf), kAutoBufSize, 0, false,
208 293786 : true);
209 293786 : }
210 :
211 293783 : nsAutoVoidArray& operator=(const nsVoidArray& other)
212 : {
213 293783 : nsVoidArray::operator=(other);
214 293781 : return *this;
215 : }
216 :
217 : protected:
218 : // The internal storage
219 : char mAutoBuf[sizeof(Impl) + (kAutoBufSize - 1) * sizeof(void*)];
220 : };
221 :
222 :
223 : //===================================================================
224 : // nsSmallVoidArray is not a general-purpose replacement for
225 : // ns(Auto)VoidArray because there is (some) extra CPU overhead for arrays
226 : // larger than 1 element, though not a lot. It is appropriate for
227 : // space-sensitive uses where sizes of 0 or 1 are moderately common or
228 : // more, and where we're NOT storing arbitrary integers or arbitrary
229 : // pointers.
230 :
231 : // NOTE: nsSmallVoidArray can ONLY be used for holding items that always
232 : // have the low bit as a 0 - i.e. element & 1 == 0. This happens to be
233 : // true for allocated and object pointers for all the architectures we run
234 : // on, but conceivably there might be some architectures/compilers for
235 : // which it is NOT true. We know this works for all existing architectures
236 : // because if it didn't then nsCheapVoidArray would have failed. Also note
237 : // that we will ASSERT if this assumption is violated in DEBUG builds.
238 :
239 : // XXX we're really re-implementing the whole nsVoidArray interface here -
240 : // some form of abstract class would be useful
241 :
242 : // I disagree on the abstraction here. If the point of this class is to be
243 : // as small as possible, and no one will ever derive from it, as I found
244 : // today, there should not be any virtualness to it to avoid the vtable
245 : // ptr overhead.
246 :
247 : class NS_COM_GLUE nsSmallVoidArray : private nsVoidArray
248 : {
249 : public:
250 : ~nsSmallVoidArray();
251 :
252 : nsSmallVoidArray& operator=(nsSmallVoidArray& other);
253 : void* operator[](PRInt32 aIndex) const { return ElementAt(aIndex); }
254 :
255 : PRInt32 GetArraySize() const;
256 :
257 : PRInt32 Count() const;
258 : void* FastElementAt(PRInt32 aIndex) const;
259 : // This both asserts and bounds-checks, because (1) we don't want
260 : // people to write bad code, but (2) we don't want to change it to
261 : // crashing for backwards compatibility. See bug 96108.
262 0 : void* ElementAt(PRInt32 aIndex) const
263 : {
264 0 : NS_ASSERTION(0 <= aIndex && aIndex < Count(), "nsSmallVoidArray::ElementAt: index out of range");
265 0 : return SafeElementAt(aIndex);
266 : }
267 0 : void* SafeElementAt(PRInt32 aIndex) const {
268 : // let compiler inline; it may be able to remove these checks
269 0 : if (PRUint32(aIndex) >= PRUint32(Count())) // handles aIndex < 0 too
270 : {
271 0 : return nsnull;
272 : }
273 0 : return FastElementAt(aIndex);
274 : }
275 : PRInt32 IndexOf(void* aPossibleElement) const;
276 : bool InsertElementAt(void* aElement, PRInt32 aIndex);
277 : bool InsertElementsAt(const nsVoidArray &other, PRInt32 aIndex);
278 : bool ReplaceElementAt(void* aElement, PRInt32 aIndex);
279 : bool MoveElement(PRInt32 aFrom, PRInt32 aTo);
280 : bool AppendElement(void* aElement);
281 : bool AppendElements(nsVoidArray& aElements) {
282 : return InsertElementsAt(aElements, Count());
283 : }
284 : bool RemoveElement(void* aElement);
285 : bool RemoveElementsAt(PRInt32 aIndex, PRInt32 aCount);
286 : bool RemoveElementAt(PRInt32 aIndex);
287 :
288 : void Clear();
289 : bool SizeTo(PRInt32 aMin);
290 : void Compact();
291 : void Sort(nsVoidArrayComparatorFunc aFunc, void* aData);
292 :
293 : bool EnumerateForwards(nsVoidArrayEnumFunc aFunc, void* aData);
294 : bool EnumerateBackwards(nsVoidArrayEnumFunc aFunc, void* aData);
295 :
296 : private:
297 :
298 2508 : bool HasSingle() const
299 : {
300 2508 : return !!(reinterpret_cast<PRWord>(mImpl) & 0x1);
301 : }
302 322 : void* GetSingle() const
303 : {
304 322 : NS_ASSERTION(HasSingle(), "wrong type");
305 : return reinterpret_cast<void*>
306 322 : (reinterpret_cast<PRWord>(mImpl) & ~0x1);
307 : }
308 122 : void SetSingle(void *aChild)
309 : {
310 122 : NS_ASSERTION(HasSingle() || !mImpl, "overwriting array");
311 : mImpl = reinterpret_cast<Impl*>
312 122 : (reinterpret_cast<PRWord>(aChild) | 0x1);
313 122 : }
314 122 : bool IsEmpty() const
315 : {
316 : // Note that this isn't the same as Count()==0
317 122 : return !mImpl;
318 : }
319 610 : const nsVoidArray* AsArray() const
320 : {
321 610 : NS_ASSERTION(!HasSingle(), "This is a single");
322 610 : return this;
323 : }
324 0 : nsVoidArray* AsArray()
325 : {
326 0 : NS_ASSERTION(!HasSingle(), "This is a single");
327 0 : return this;
328 : }
329 : bool EnsureArray();
330 : };
331 :
332 : #endif /* nsVoidArray_h___ */
|