|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; c-file-offsets: ((substatement-open . 0)) -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 #ifndef nsVoidArray_h___ |
|
6 #define nsVoidArray_h___ |
|
7 |
|
8 //#define DEBUG_VOIDARRAY 1 |
|
9 |
|
10 #include "nsDebug.h" |
|
11 |
|
12 #include "mozilla/MemoryReporting.h" |
|
13 #include <stdint.h> |
|
14 |
|
15 // Comparator callback function for sorting array values. |
|
16 typedef int (* nsVoidArrayComparatorFunc) |
|
17 (const void* aElement1, const void* aElement2, void* aData); |
|
18 |
|
19 // Enumerator callback function. Return false to stop |
|
20 typedef bool (* nsVoidArrayEnumFunc)(void* aElement, void *aData); |
|
21 typedef bool (* nsVoidArrayEnumFuncConst)(const void* aElement, void *aData); |
|
22 |
|
23 // SizeOfExcludingThis callback function. |
|
24 typedef size_t (* nsVoidArraySizeOfElementIncludingThisFunc)(const void* aElement, |
|
25 mozilla::MallocSizeOf aMallocSizeOf, |
|
26 void *aData); |
|
27 |
|
28 /// A basic zero-based array of void*'s that manages its own memory |
|
29 class NS_COM_GLUE nsVoidArray { |
|
30 public: |
|
31 nsVoidArray(); |
|
32 nsVoidArray(int32_t aCount); // initial count of aCount elements set to nullptr |
|
33 ~nsVoidArray(); |
|
34 |
|
35 nsVoidArray& operator=(const nsVoidArray& other); |
|
36 |
|
37 inline int32_t Count() const { |
|
38 return mImpl ? mImpl->mCount : 0; |
|
39 } |
|
40 // If the array grows, the newly created entries will all be null |
|
41 bool SetCount(int32_t aNewCount); |
|
42 // returns the max number that can be held without allocating |
|
43 inline int32_t GetArraySize() const { |
|
44 return mImpl ? mImpl->mSize : 0; |
|
45 } |
|
46 |
|
47 void* FastElementAt(int32_t aIndex) const |
|
48 { |
|
49 NS_ASSERTION(0 <= aIndex && aIndex < Count(), "nsVoidArray::FastElementAt: index out of range"); |
|
50 return mImpl->mArray[aIndex]; |
|
51 } |
|
52 |
|
53 // This both asserts and bounds-checks, because (1) we don't want |
|
54 // people to write bad code, but (2) we don't want to change it to |
|
55 // crashing for backwards compatibility. See bug 96108. |
|
56 void* ElementAt(int32_t aIndex) const |
|
57 { |
|
58 NS_ASSERTION(0 <= aIndex && aIndex < Count(), "nsVoidArray::ElementAt: index out of range"); |
|
59 return SafeElementAt(aIndex); |
|
60 } |
|
61 |
|
62 // bounds-checked version |
|
63 void* SafeElementAt(int32_t aIndex) const |
|
64 { |
|
65 if (uint32_t(aIndex) >= uint32_t(Count())) // handles aIndex < 0 too |
|
66 { |
|
67 return nullptr; |
|
68 } |
|
69 // The bounds check ensures mImpl is non-null. |
|
70 return mImpl->mArray[aIndex]; |
|
71 } |
|
72 |
|
73 void* operator[](int32_t aIndex) const { return ElementAt(aIndex); } |
|
74 |
|
75 int32_t IndexOf(void* aPossibleElement) const; |
|
76 |
|
77 bool InsertElementAt(void* aElement, int32_t aIndex); |
|
78 bool InsertElementsAt(const nsVoidArray &other, int32_t aIndex); |
|
79 |
|
80 bool ReplaceElementAt(void* aElement, int32_t aIndex); |
|
81 |
|
82 // useful for doing LRU arrays, sorting, etc |
|
83 bool MoveElement(int32_t aFrom, int32_t aTo); |
|
84 |
|
85 bool AppendElement(void* aElement) { |
|
86 return InsertElementAt(aElement, Count()); |
|
87 } |
|
88 |
|
89 bool AppendElements(nsVoidArray& aElements) { |
|
90 return InsertElementsAt(aElements, Count()); |
|
91 } |
|
92 |
|
93 bool RemoveElement(void* aElement); |
|
94 void RemoveElementsAt(int32_t aIndex, int32_t aCount); |
|
95 void RemoveElementAt(int32_t aIndex) { return RemoveElementsAt(aIndex,1); } |
|
96 |
|
97 void Clear(); |
|
98 |
|
99 bool SizeTo(int32_t aMin); |
|
100 // Subtly different - Compact() tries to be smart about whether we |
|
101 // should reallocate the array; SizeTo() always reallocates. |
|
102 void Compact(); |
|
103 |
|
104 void Sort(nsVoidArrayComparatorFunc aFunc, void* aData); |
|
105 |
|
106 bool EnumerateForwards(nsVoidArrayEnumFunc aFunc, void* aData); |
|
107 bool EnumerateForwards(nsVoidArrayEnumFuncConst aFunc, void* aData) const; |
|
108 bool EnumerateBackwards(nsVoidArrayEnumFunc aFunc, void* aData); |
|
109 |
|
110 // Measures the size of the array's element storage, and if |
|
111 // |aSizeOfElementIncludingThis| is non-nullptr, measures the size of things |
|
112 // pointed to by elements. |
|
113 size_t SizeOfExcludingThis( |
|
114 nsVoidArraySizeOfElementIncludingThisFunc aSizeOfElementIncludingThis, |
|
115 mozilla::MallocSizeOf aMallocSizeOf, void* aData = nullptr) const; |
|
116 |
|
117 protected: |
|
118 bool GrowArrayBy(int32_t aGrowBy); |
|
119 |
|
120 struct Impl { |
|
121 /** |
|
122 * The actual array size. |
|
123 */ |
|
124 int32_t mSize; |
|
125 |
|
126 /** |
|
127 * The number of elements in the array |
|
128 */ |
|
129 int32_t mCount; |
|
130 |
|
131 /** |
|
132 * Array data, padded out to the actual size of the array. |
|
133 */ |
|
134 void* mArray[1]; |
|
135 }; |
|
136 |
|
137 Impl* mImpl; |
|
138 #if DEBUG_VOIDARRAY |
|
139 int32_t mMaxCount; |
|
140 int32_t mMaxSize; |
|
141 bool mIsAuto; |
|
142 #endif |
|
143 |
|
144 // bit twiddlers |
|
145 void SetArray(Impl *newImpl, int32_t aSize, int32_t aCount); |
|
146 |
|
147 private: |
|
148 /// Copy constructors are not allowed |
|
149 nsVoidArray(const nsVoidArray& other); |
|
150 }; |
|
151 |
|
152 //=================================================================== |
|
153 // nsSmallVoidArray is not a general-purpose replacement for |
|
154 // ns(Auto)VoidArray because there is (some) extra CPU overhead for arrays |
|
155 // larger than 1 element, though not a lot. It is appropriate for |
|
156 // space-sensitive uses where sizes of 0 or 1 are moderately common or |
|
157 // more, and where we're NOT storing arbitrary integers or arbitrary |
|
158 // pointers. |
|
159 |
|
160 // NOTE: nsSmallVoidArray can ONLY be used for holding items that always |
|
161 // have the low bit as a 0 - i.e. element & 1 == 0. This happens to be |
|
162 // true for allocated and object pointers for all the architectures we run |
|
163 // on, but conceivably there might be some architectures/compilers for |
|
164 // which it is NOT true. We know this works for all existing architectures |
|
165 // because if it didn't then nsCheapVoidArray would have failed. Also note |
|
166 // that we will ASSERT if this assumption is violated in DEBUG builds. |
|
167 |
|
168 // XXX we're really re-implementing the whole nsVoidArray interface here - |
|
169 // some form of abstract class would be useful |
|
170 |
|
171 // I disagree on the abstraction here. If the point of this class is to be |
|
172 // as small as possible, and no one will ever derive from it, as I found |
|
173 // today, there should not be any virtualness to it to avoid the vtable |
|
174 // ptr overhead. |
|
175 |
|
176 class NS_COM_GLUE nsSmallVoidArray : private nsVoidArray |
|
177 { |
|
178 public: |
|
179 ~nsSmallVoidArray(); |
|
180 |
|
181 nsSmallVoidArray& operator=(nsSmallVoidArray& other); |
|
182 void* operator[](int32_t aIndex) const { return ElementAt(aIndex); } |
|
183 |
|
184 int32_t GetArraySize() const; |
|
185 |
|
186 int32_t Count() const; |
|
187 void* FastElementAt(int32_t aIndex) const; |
|
188 // This both asserts and bounds-checks, because (1) we don't want |
|
189 // people to write bad code, but (2) we don't want to change it to |
|
190 // crashing for backwards compatibility. See bug 96108. |
|
191 void* ElementAt(int32_t aIndex) const |
|
192 { |
|
193 NS_ASSERTION(0 <= aIndex && aIndex < Count(), "nsSmallVoidArray::ElementAt: index out of range"); |
|
194 return SafeElementAt(aIndex); |
|
195 } |
|
196 void* SafeElementAt(int32_t aIndex) const { |
|
197 // let compiler inline; it may be able to remove these checks |
|
198 if (uint32_t(aIndex) >= uint32_t(Count())) // handles aIndex < 0 too |
|
199 { |
|
200 return nullptr; |
|
201 } |
|
202 return FastElementAt(aIndex); |
|
203 } |
|
204 int32_t IndexOf(void* aPossibleElement) const; |
|
205 bool InsertElementAt(void* aElement, int32_t aIndex); |
|
206 bool InsertElementsAt(const nsVoidArray &other, int32_t aIndex); |
|
207 bool ReplaceElementAt(void* aElement, int32_t aIndex); |
|
208 bool MoveElement(int32_t aFrom, int32_t aTo); |
|
209 bool AppendElement(void* aElement); |
|
210 bool AppendElements(nsVoidArray& aElements) { |
|
211 return InsertElementsAt(aElements, Count()); |
|
212 } |
|
213 bool RemoveElement(void* aElement); |
|
214 void RemoveElementsAt(int32_t aIndex, int32_t aCount); |
|
215 void RemoveElementAt(int32_t aIndex); |
|
216 |
|
217 void Clear(); |
|
218 bool SizeTo(int32_t aMin); |
|
219 void Compact(); |
|
220 void Sort(nsVoidArrayComparatorFunc aFunc, void* aData); |
|
221 |
|
222 bool EnumerateForwards(nsVoidArrayEnumFunc aFunc, void* aData); |
|
223 bool EnumerateBackwards(nsVoidArrayEnumFunc aFunc, void* aData); |
|
224 |
|
225 private: |
|
226 |
|
227 bool HasSingle() const |
|
228 { |
|
229 return !!(reinterpret_cast<intptr_t>(mImpl) & 0x1); |
|
230 } |
|
231 void* GetSingle() const |
|
232 { |
|
233 NS_ASSERTION(HasSingle(), "wrong type"); |
|
234 return reinterpret_cast<void*> |
|
235 (reinterpret_cast<intptr_t>(mImpl) & ~0x1); |
|
236 } |
|
237 void SetSingle(void *aChild) |
|
238 { |
|
239 NS_ASSERTION(HasSingle() || !mImpl, "overwriting array"); |
|
240 mImpl = reinterpret_cast<Impl*> |
|
241 (reinterpret_cast<intptr_t>(aChild) | 0x1); |
|
242 } |
|
243 bool IsEmpty() const |
|
244 { |
|
245 // Note that this isn't the same as Count()==0 |
|
246 return !mImpl; |
|
247 } |
|
248 const nsVoidArray* AsArray() const |
|
249 { |
|
250 NS_ASSERTION(!HasSingle(), "This is a single"); |
|
251 return this; |
|
252 } |
|
253 nsVoidArray* AsArray() |
|
254 { |
|
255 NS_ASSERTION(!HasSingle(), "This is a single"); |
|
256 return this; |
|
257 } |
|
258 bool EnsureArray(); |
|
259 }; |
|
260 |
|
261 #endif /* nsVoidArray_h___ */ |