|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */ |
|
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 #ifndef nsTArray_h__ |
|
8 #define nsTArray_h__ |
|
9 |
|
10 #include "nsTArrayForwardDeclare.h" |
|
11 #include "mozilla/Alignment.h" |
|
12 #include "mozilla/Assertions.h" |
|
13 #include "mozilla/MemoryReporting.h" |
|
14 #include "mozilla/TypeTraits.h" |
|
15 |
|
16 #include <string.h> |
|
17 |
|
18 #include "nsCycleCollectionNoteChild.h" |
|
19 #include "nsAlgorithm.h" |
|
20 #include "nscore.h" |
|
21 #include "nsQuickSort.h" |
|
22 #include "nsDebug.h" |
|
23 #include "nsISupportsImpl.h" |
|
24 #include <new> |
|
25 |
|
26 namespace JS { |
|
27 template <class T> |
|
28 class Heap; |
|
29 } /* namespace JS */ |
|
30 |
|
31 class nsRegion; |
|
32 class nsIntRegion; |
|
33 |
|
34 // |
|
35 // nsTArray is a resizable array class, like std::vector. |
|
36 // |
|
37 // Unlike std::vector, which follows C++'s construction/destruction rules, |
|
38 // nsTArray assumes that your "T" can be memmoved()'ed safely. |
|
39 // |
|
40 // The public classes defined in this header are |
|
41 // |
|
42 // nsTArray<T>, |
|
43 // FallibleTArray<T>, |
|
44 // nsAutoTArray<T, N>, and |
|
45 // AutoFallibleTArray<T, N>. |
|
46 // |
|
47 // nsTArray and nsAutoTArray are infallible; if one tries to make an allocation |
|
48 // which fails, it crashes the program. In contrast, FallibleTArray and |
|
49 // AutoFallibleTArray are fallible; if you use one of these classes, you must |
|
50 // check the return values of methods such as Append() which may allocate. If |
|
51 // in doubt, choose an infallible type. |
|
52 // |
|
53 // InfallibleTArray and AutoInfallibleTArray are aliases for nsTArray and |
|
54 // nsAutoTArray. |
|
55 // |
|
56 // If you just want to declare the nsTArray types (e.g., if you're in a header |
|
57 // file and don't need the full nsTArray definitions) consider including |
|
58 // nsTArrayForwardDeclare.h instead of nsTArray.h. |
|
59 // |
|
60 // The template parameter (i.e., T in nsTArray<T>) specifies the type of the |
|
61 // elements and has the following requirements: |
|
62 // |
|
63 // T MUST be safely memmove()'able. |
|
64 // T MUST define a copy-constructor. |
|
65 // T MAY define operator< for sorting. |
|
66 // T MAY define operator== for searching. |
|
67 // |
|
68 // (Note that the memmove requirement may be relaxed for certain types - see |
|
69 // nsTArray_CopyChooser below.) |
|
70 // |
|
71 // For methods taking a Comparator instance, the Comparator must be a class |
|
72 // defining the following methods: |
|
73 // |
|
74 // class Comparator { |
|
75 // public: |
|
76 // /** @return True if the elements are equals; false otherwise. */ |
|
77 // bool Equals(const elem_type& a, const Item& b) const; |
|
78 // |
|
79 // /** @return True if (a < b); false otherwise. */ |
|
80 // bool LessThan(const elem_type& a, const Item& b) const; |
|
81 // }; |
|
82 // |
|
83 // The Equals method is used for searching, and the LessThan method is used for |
|
84 // searching and sorting. The |Item| type above can be arbitrary, but must |
|
85 // match the Item type passed to the sort or search function. |
|
86 // |
|
87 |
|
88 |
|
89 // |
|
90 // nsTArrayFallibleResult and nsTArrayInfallibleResult types are proxy types |
|
91 // which are used because you cannot use a templated type which is bound to |
|
92 // void as an argument to a void function. In order to work around that, we |
|
93 // encode either a void or a boolean inside these proxy objects, and pass them |
|
94 // to the aforementioned function instead, and then use the type information to |
|
95 // decide what to do in the function. |
|
96 // |
|
97 // Note that public nsTArray methods should never return a proxy type. Such |
|
98 // types are only meant to be used in the internal nsTArray helper methods. |
|
99 // Public methods returning non-proxy types cannot be called from other |
|
100 // nsTArray members. |
|
101 // |
|
102 struct nsTArrayFallibleResult |
|
103 { |
|
104 // Note: allows implicit conversions from and to bool |
|
105 nsTArrayFallibleResult(bool result) |
|
106 : mResult(result) |
|
107 {} |
|
108 |
|
109 operator bool() { |
|
110 return mResult; |
|
111 } |
|
112 |
|
113 private: |
|
114 bool mResult; |
|
115 }; |
|
116 |
|
117 struct nsTArrayInfallibleResult |
|
118 { |
|
119 }; |
|
120 |
|
121 // |
|
122 // nsTArray*Allocators must all use the same |free()|, to allow swap()'ing |
|
123 // between fallible and infallible variants. |
|
124 // |
|
125 |
|
126 struct nsTArrayFallibleAllocatorBase |
|
127 { |
|
128 typedef bool ResultType; |
|
129 typedef nsTArrayFallibleResult ResultTypeProxy; |
|
130 |
|
131 static ResultType Result(ResultTypeProxy result) { |
|
132 return result; |
|
133 } |
|
134 |
|
135 static bool Successful(ResultTypeProxy result) { |
|
136 return result; |
|
137 } |
|
138 |
|
139 static ResultTypeProxy SuccessResult() { |
|
140 return true; |
|
141 } |
|
142 |
|
143 static ResultTypeProxy FailureResult() { |
|
144 return false; |
|
145 } |
|
146 |
|
147 static ResultType ConvertBoolToResultType(bool aValue) { |
|
148 return aValue; |
|
149 } |
|
150 }; |
|
151 |
|
152 struct nsTArrayInfallibleAllocatorBase |
|
153 { |
|
154 typedef void ResultType; |
|
155 typedef nsTArrayInfallibleResult ResultTypeProxy; |
|
156 |
|
157 static ResultType Result(ResultTypeProxy result) { |
|
158 } |
|
159 |
|
160 static bool Successful(ResultTypeProxy) { |
|
161 return true; |
|
162 } |
|
163 |
|
164 static ResultTypeProxy SuccessResult() { |
|
165 return ResultTypeProxy(); |
|
166 } |
|
167 |
|
168 static ResultTypeProxy FailureResult() { |
|
169 NS_RUNTIMEABORT("Infallible nsTArray should never fail"); |
|
170 return ResultTypeProxy(); |
|
171 } |
|
172 |
|
173 static ResultType ConvertBoolToResultType(bool aValue) { |
|
174 if (!aValue) { |
|
175 NS_RUNTIMEABORT("infallible nsTArray should never convert false to ResultType"); |
|
176 } |
|
177 } |
|
178 }; |
|
179 |
|
180 #if defined(MOZALLOC_HAVE_XMALLOC) |
|
181 #include "mozilla/mozalloc_abort.h" |
|
182 |
|
183 struct nsTArrayFallibleAllocator : nsTArrayFallibleAllocatorBase |
|
184 { |
|
185 static void* Malloc(size_t size) { |
|
186 return moz_malloc(size); |
|
187 } |
|
188 |
|
189 static void* Realloc(void* ptr, size_t size) { |
|
190 return moz_realloc(ptr, size); |
|
191 } |
|
192 |
|
193 static void Free(void* ptr) { |
|
194 moz_free(ptr); |
|
195 } |
|
196 |
|
197 static void SizeTooBig(size_t) { |
|
198 } |
|
199 }; |
|
200 |
|
201 struct nsTArrayInfallibleAllocator : nsTArrayInfallibleAllocatorBase |
|
202 { |
|
203 static void* Malloc(size_t size) { |
|
204 return moz_xmalloc(size); |
|
205 } |
|
206 |
|
207 static void* Realloc(void* ptr, size_t size) { |
|
208 return moz_xrealloc(ptr, size); |
|
209 } |
|
210 |
|
211 static void Free(void* ptr) { |
|
212 moz_free(ptr); |
|
213 } |
|
214 |
|
215 static void SizeTooBig(size_t size) { |
|
216 NS_ABORT_OOM(size); |
|
217 } |
|
218 }; |
|
219 |
|
220 #else |
|
221 #include <stdlib.h> |
|
222 |
|
223 struct nsTArrayFallibleAllocator : nsTArrayFallibleAllocatorBase |
|
224 { |
|
225 static void* Malloc(size_t size) { |
|
226 return malloc(size); |
|
227 } |
|
228 |
|
229 static void* Realloc(void* ptr, size_t size) { |
|
230 return realloc(ptr, size); |
|
231 } |
|
232 |
|
233 static void Free(void* ptr) { |
|
234 free(ptr); |
|
235 } |
|
236 |
|
237 static void SizeTooBig(size_t) { |
|
238 } |
|
239 }; |
|
240 |
|
241 struct nsTArrayInfallibleAllocator : nsTArrayInfallibleAllocatorBase |
|
242 { |
|
243 static void* Malloc(size_t size) { |
|
244 void* ptr = malloc(size); |
|
245 if (MOZ_UNLIKELY(!ptr)) { |
|
246 NS_ABORT_OOM(size); |
|
247 } |
|
248 return ptr; |
|
249 } |
|
250 |
|
251 static void* Realloc(void* ptr, size_t size) { |
|
252 void* newptr = realloc(ptr, size); |
|
253 if (MOZ_UNLIKELY(!ptr && size)) { |
|
254 NS_ABORT_OOM(size); |
|
255 } |
|
256 return newptr; |
|
257 } |
|
258 |
|
259 static void Free(void* ptr) { |
|
260 free(ptr); |
|
261 } |
|
262 |
|
263 static void SizeTooBig(size_t size) { |
|
264 NS_ABORT_OOM(size); |
|
265 } |
|
266 }; |
|
267 |
|
268 #endif |
|
269 |
|
270 // nsTArray_base stores elements into the space allocated beyond |
|
271 // sizeof(*this). This is done to minimize the size of the nsTArray |
|
272 // object when it is empty. |
|
273 struct NS_COM_GLUE nsTArrayHeader |
|
274 { |
|
275 static nsTArrayHeader sEmptyHdr; |
|
276 |
|
277 uint32_t mLength; |
|
278 uint32_t mCapacity : 31; |
|
279 uint32_t mIsAutoArray : 1; |
|
280 }; |
|
281 |
|
282 // This class provides a SafeElementAt method to nsTArray<T*> which does |
|
283 // not take a second default value parameter. |
|
284 template <class E, class Derived> |
|
285 struct nsTArray_SafeElementAtHelper |
|
286 { |
|
287 typedef E* elem_type; |
|
288 typedef uint32_t index_type; |
|
289 |
|
290 // No implementation is provided for these two methods, and that is on |
|
291 // purpose, since we don't support these functions on non-pointer type |
|
292 // instantiations. |
|
293 elem_type& SafeElementAt(index_type i); |
|
294 const elem_type& SafeElementAt(index_type i) const; |
|
295 }; |
|
296 |
|
297 template <class E, class Derived> |
|
298 struct nsTArray_SafeElementAtHelper<E*, Derived> |
|
299 { |
|
300 typedef E* elem_type; |
|
301 typedef uint32_t index_type; |
|
302 |
|
303 elem_type SafeElementAt(index_type i) { |
|
304 return static_cast<Derived*> (this)->SafeElementAt(i, nullptr); |
|
305 } |
|
306 |
|
307 const elem_type SafeElementAt(index_type i) const { |
|
308 return static_cast<const Derived*> (this)->SafeElementAt(i, nullptr); |
|
309 } |
|
310 }; |
|
311 |
|
312 // E is the base type that the smart pointer is templated over; the |
|
313 // smart pointer can act as E*. |
|
314 template <class E, class Derived> |
|
315 struct nsTArray_SafeElementAtSmartPtrHelper |
|
316 { |
|
317 typedef E* elem_type; |
|
318 typedef uint32_t index_type; |
|
319 |
|
320 elem_type SafeElementAt(index_type i) { |
|
321 return static_cast<Derived*> (this)->SafeElementAt(i, nullptr); |
|
322 } |
|
323 |
|
324 const elem_type SafeElementAt(index_type i) const { |
|
325 return static_cast<const Derived*> (this)->SafeElementAt(i, nullptr); |
|
326 } |
|
327 }; |
|
328 |
|
329 template <class T> class nsCOMPtr; |
|
330 |
|
331 template <class E, class Derived> |
|
332 struct nsTArray_SafeElementAtHelper<nsCOMPtr<E>, Derived> : |
|
333 public nsTArray_SafeElementAtSmartPtrHelper<E, Derived> |
|
334 { |
|
335 }; |
|
336 |
|
337 template <class T> class nsRefPtr; |
|
338 |
|
339 template <class E, class Derived> |
|
340 struct nsTArray_SafeElementAtHelper<nsRefPtr<E>, Derived> : |
|
341 public nsTArray_SafeElementAtSmartPtrHelper<E, Derived> |
|
342 { |
|
343 }; |
|
344 |
|
345 // |
|
346 // This class serves as a base class for nsTArray. It shouldn't be used |
|
347 // directly. It holds common implementation code that does not depend on the |
|
348 // element type of the nsTArray. |
|
349 // |
|
350 template<class Alloc, class Copy> |
|
351 class nsTArray_base |
|
352 { |
|
353 // Allow swapping elements with |nsTArray_base|s created using a |
|
354 // different allocator. This is kosher because all allocators use |
|
355 // the same free(). |
|
356 template<class Allocator, class Copier> |
|
357 friend class nsTArray_base; |
|
358 |
|
359 protected: |
|
360 typedef nsTArrayHeader Header; |
|
361 |
|
362 public: |
|
363 typedef uint32_t size_type; |
|
364 typedef uint32_t index_type; |
|
365 |
|
366 // @return The number of elements in the array. |
|
367 size_type Length() const { |
|
368 return mHdr->mLength; |
|
369 } |
|
370 |
|
371 // @return True if the array is empty or false otherwise. |
|
372 bool IsEmpty() const { |
|
373 return Length() == 0; |
|
374 } |
|
375 |
|
376 // @return The number of elements that can fit in the array without forcing |
|
377 // the array to be re-allocated. The length of an array is always less |
|
378 // than or equal to its capacity. |
|
379 size_type Capacity() const { |
|
380 return mHdr->mCapacity; |
|
381 } |
|
382 |
|
383 #ifdef DEBUG |
|
384 void* DebugGetHeader() const { |
|
385 return mHdr; |
|
386 } |
|
387 #endif |
|
388 |
|
389 protected: |
|
390 nsTArray_base(); |
|
391 |
|
392 ~nsTArray_base(); |
|
393 |
|
394 // Resize the storage if necessary to achieve the requested capacity. |
|
395 // @param capacity The requested number of array elements. |
|
396 // @param elemSize The size of an array element. |
|
397 // @return False if insufficient memory is available; true otherwise. |
|
398 typename Alloc::ResultTypeProxy EnsureCapacity(size_type capacity, size_type elemSize); |
|
399 |
|
400 // Resize the storage to the minimum required amount. |
|
401 // @param elemSize The size of an array element. |
|
402 // @param elemAlign The alignment in bytes of an array element. |
|
403 void ShrinkCapacity(size_type elemSize, size_t elemAlign); |
|
404 |
|
405 // This method may be called to resize a "gap" in the array by shifting |
|
406 // elements around. It updates mLength appropriately. If the resulting |
|
407 // array has zero elements, then the array's memory is free'd. |
|
408 // @param start The starting index of the gap. |
|
409 // @param oldLen The current length of the gap. |
|
410 // @param newLen The desired length of the gap. |
|
411 // @param elemSize The size of an array element. |
|
412 // @param elemAlign The alignment in bytes of an array element. |
|
413 void ShiftData(index_type start, size_type oldLen, size_type newLen, |
|
414 size_type elemSize, size_t elemAlign); |
|
415 |
|
416 // This method increments the length member of the array's header. |
|
417 // Note that mHdr may actually be sEmptyHdr in the case where a |
|
418 // zero-length array is inserted into our array. But then n should |
|
419 // always be 0. |
|
420 void IncrementLength(uint32_t n) { |
|
421 if (mHdr == EmptyHdr()) { |
|
422 if (MOZ_UNLIKELY(n != 0)) { |
|
423 // Writing a non-zero length to the empty header would be extremely bad. |
|
424 MOZ_CRASH(); |
|
425 } |
|
426 } else { |
|
427 mHdr->mLength += n; |
|
428 } |
|
429 } |
|
430 |
|
431 // This method inserts blank slots into the array. |
|
432 // @param index the place to insert the new elements. This must be no |
|
433 // greater than the current length of the array. |
|
434 // @param count the number of slots to insert |
|
435 // @param elementSize the size of an array element. |
|
436 // @param elemAlign the alignment in bytes of an array element. |
|
437 bool InsertSlotsAt(index_type index, size_type count, |
|
438 size_type elementSize, size_t elemAlign); |
|
439 |
|
440 protected: |
|
441 template<class Allocator> |
|
442 typename Alloc::ResultTypeProxy |
|
443 SwapArrayElements(nsTArray_base<Allocator, Copy>& other, |
|
444 size_type elemSize, |
|
445 size_t elemAlign); |
|
446 |
|
447 // This is an RAII class used in SwapArrayElements. |
|
448 class IsAutoArrayRestorer { |
|
449 public: |
|
450 IsAutoArrayRestorer(nsTArray_base<Alloc, Copy> &array, size_t elemAlign); |
|
451 ~IsAutoArrayRestorer(); |
|
452 |
|
453 private: |
|
454 nsTArray_base<Alloc, Copy> &mArray; |
|
455 size_t mElemAlign; |
|
456 bool mIsAuto; |
|
457 }; |
|
458 |
|
459 // Helper function for SwapArrayElements. Ensures that if the array |
|
460 // is an nsAutoTArray that it doesn't use the built-in buffer. |
|
461 bool EnsureNotUsingAutoArrayBuffer(size_type elemSize); |
|
462 |
|
463 // Returns true if this nsTArray is an nsAutoTArray with a built-in buffer. |
|
464 bool IsAutoArray() const { |
|
465 return mHdr->mIsAutoArray; |
|
466 } |
|
467 |
|
468 // Returns a Header for the built-in buffer of this nsAutoTArray. |
|
469 Header* GetAutoArrayBuffer(size_t elemAlign) { |
|
470 MOZ_ASSERT(IsAutoArray(), "Should be an auto array to call this"); |
|
471 return GetAutoArrayBufferUnsafe(elemAlign); |
|
472 } |
|
473 const Header* GetAutoArrayBuffer(size_t elemAlign) const { |
|
474 MOZ_ASSERT(IsAutoArray(), "Should be an auto array to call this"); |
|
475 return GetAutoArrayBufferUnsafe(elemAlign); |
|
476 } |
|
477 |
|
478 // Returns a Header for the built-in buffer of this nsAutoTArray, but doesn't |
|
479 // assert that we are an nsAutoTArray. |
|
480 Header* GetAutoArrayBufferUnsafe(size_t elemAlign) { |
|
481 return const_cast<Header*>(static_cast<const nsTArray_base<Alloc, Copy>*>(this)-> |
|
482 GetAutoArrayBufferUnsafe(elemAlign)); |
|
483 } |
|
484 const Header* GetAutoArrayBufferUnsafe(size_t elemAlign) const; |
|
485 |
|
486 // Returns true if this is an nsAutoTArray and it currently uses the |
|
487 // built-in buffer to store its elements. |
|
488 bool UsesAutoArrayBuffer() const; |
|
489 |
|
490 // The array's elements (prefixed with a Header). This pointer is never |
|
491 // null. If the array is empty, then this will point to sEmptyHdr. |
|
492 Header *mHdr; |
|
493 |
|
494 Header* Hdr() const { |
|
495 return mHdr; |
|
496 } |
|
497 |
|
498 Header** PtrToHdr() { |
|
499 return &mHdr; |
|
500 } |
|
501 |
|
502 static Header* EmptyHdr() { |
|
503 return &Header::sEmptyHdr; |
|
504 } |
|
505 }; |
|
506 |
|
507 // |
|
508 // This class defines convenience functions for element specific operations. |
|
509 // Specialize this template if necessary. |
|
510 // |
|
511 template<class E> |
|
512 class nsTArrayElementTraits |
|
513 { |
|
514 public: |
|
515 // Invoke the default constructor in place. |
|
516 static inline void Construct(E *e) { |
|
517 // Do NOT call "E()"! That triggers C++ "default initialization" |
|
518 // which zeroes out POD ("plain old data") types such as regular |
|
519 // ints. We don't want that because it can be a performance issue |
|
520 // and people don't expect it; nsTArray should work like a regular |
|
521 // C/C++ array in this respect. |
|
522 new (static_cast<void *>(e)) E; |
|
523 } |
|
524 // Invoke the copy-constructor in place. |
|
525 template<class A> |
|
526 static inline void Construct(E *e, const A &arg) { |
|
527 typedef typename mozilla::RemoveCV<E>::Type E_NoCV; |
|
528 typedef typename mozilla::RemoveCV<A>::Type A_NoCV; |
|
529 static_assert(!mozilla::IsSame<E_NoCV*, A_NoCV>::value, |
|
530 "For safety, we disallow constructing nsTArray<E> elements " |
|
531 "from E* pointers. See bug 960591."); |
|
532 new (static_cast<void *>(e)) E(arg); |
|
533 } |
|
534 // Invoke the destructor in place. |
|
535 static inline void Destruct(E *e) { |
|
536 e->~E(); |
|
537 } |
|
538 }; |
|
539 |
|
540 // The default comparator used by nsTArray |
|
541 template<class A, class B> |
|
542 class nsDefaultComparator |
|
543 { |
|
544 public: |
|
545 bool Equals(const A& a, const B& b) const { |
|
546 return a == b; |
|
547 } |
|
548 bool LessThan(const A& a, const B& b) const { |
|
549 return a < b; |
|
550 } |
|
551 }; |
|
552 |
|
553 template <class E> class InfallibleTArray; |
|
554 template <class E> class FallibleTArray; |
|
555 |
|
556 template<bool IsPod, bool IsSameType> |
|
557 struct AssignRangeAlgorithm { |
|
558 template<class Item, class ElemType, class IndexType, class SizeType> |
|
559 static void implementation(ElemType* elements, IndexType start, |
|
560 SizeType count, const Item *values) { |
|
561 ElemType *iter = elements + start, *end = iter + count; |
|
562 for (; iter != end; ++iter, ++values) |
|
563 nsTArrayElementTraits<ElemType>::Construct(iter, *values); |
|
564 } |
|
565 }; |
|
566 |
|
567 template<> |
|
568 struct AssignRangeAlgorithm<true, true> { |
|
569 template<class Item, class ElemType, class IndexType, class SizeType> |
|
570 static void implementation(ElemType* elements, IndexType start, |
|
571 SizeType count, const Item *values) { |
|
572 memcpy(elements + start, values, count * sizeof(ElemType)); |
|
573 } |
|
574 }; |
|
575 |
|
576 // |
|
577 // Normally elements are copied with memcpy and memmove, but for some element |
|
578 // types that is problematic. The nsTArray_CopyChooser template class can be |
|
579 // specialized to ensure that copying calls constructors and destructors |
|
580 // instead, as is done below for JS::Heap<E> elements. |
|
581 // |
|
582 |
|
583 // |
|
584 // A class that defines how to copy elements using memcpy/memmove. |
|
585 // |
|
586 struct nsTArray_CopyWithMemutils |
|
587 { |
|
588 const static bool allowRealloc = true; |
|
589 |
|
590 static void CopyElements(void* dest, const void* src, size_t count, size_t elemSize) { |
|
591 memcpy(dest, src, count * elemSize); |
|
592 } |
|
593 |
|
594 static void CopyHeaderAndElements(void* dest, const void* src, size_t count, size_t elemSize) { |
|
595 memcpy(dest, src, sizeof(nsTArrayHeader) + count * elemSize); |
|
596 } |
|
597 |
|
598 static void MoveElements(void* dest, const void* src, size_t count, size_t elemSize) { |
|
599 memmove(dest, src, count * elemSize); |
|
600 } |
|
601 }; |
|
602 |
|
603 // |
|
604 // A template class that defines how to copy elements calling their constructors |
|
605 // and destructors appropriately. |
|
606 // |
|
607 template <class ElemType> |
|
608 struct nsTArray_CopyWithConstructors |
|
609 { |
|
610 typedef nsTArrayElementTraits<ElemType> traits; |
|
611 |
|
612 const static bool allowRealloc = false; |
|
613 |
|
614 static void CopyElements(void* dest, void* src, size_t count, size_t elemSize) { |
|
615 ElemType* destElem = static_cast<ElemType*>(dest); |
|
616 ElemType* srcElem = static_cast<ElemType*>(src); |
|
617 ElemType* destElemEnd = destElem + count; |
|
618 #ifdef DEBUG |
|
619 ElemType* srcElemEnd = srcElem + count; |
|
620 MOZ_ASSERT(srcElemEnd <= destElem || srcElemEnd > destElemEnd); |
|
621 #endif |
|
622 while (destElem != destElemEnd) { |
|
623 traits::Construct(destElem, *srcElem); |
|
624 traits::Destruct(srcElem); |
|
625 ++destElem; |
|
626 ++srcElem; |
|
627 } |
|
628 } |
|
629 |
|
630 static void CopyHeaderAndElements(void* dest, void* src, size_t count, size_t elemSize) { |
|
631 nsTArrayHeader* destHeader = static_cast<nsTArrayHeader*>(dest); |
|
632 nsTArrayHeader* srcHeader = static_cast<nsTArrayHeader*>(src); |
|
633 *destHeader = *srcHeader; |
|
634 CopyElements(static_cast<uint8_t*>(dest) + sizeof(nsTArrayHeader), |
|
635 static_cast<uint8_t*>(src) + sizeof(nsTArrayHeader), |
|
636 count, elemSize); |
|
637 } |
|
638 |
|
639 static void MoveElements(void* dest, void* src, size_t count, size_t elemSize) { |
|
640 ElemType* destElem = static_cast<ElemType*>(dest); |
|
641 ElemType* srcElem = static_cast<ElemType*>(src); |
|
642 ElemType* destElemEnd = destElem + count; |
|
643 ElemType* srcElemEnd = srcElem + count; |
|
644 if (destElem == srcElem) { |
|
645 return; // In practice, we don't do this. |
|
646 } else if (srcElemEnd > destElem && srcElemEnd < destElemEnd) { |
|
647 while (destElemEnd != destElem) { |
|
648 --destElemEnd; |
|
649 --srcElemEnd; |
|
650 traits::Construct(destElemEnd, *srcElemEnd); |
|
651 traits::Destruct(srcElem); |
|
652 } |
|
653 } else { |
|
654 CopyElements(dest, src, count, elemSize); |
|
655 } |
|
656 } |
|
657 }; |
|
658 |
|
659 // |
|
660 // The default behaviour is to use memcpy/memmove for everything. |
|
661 // |
|
662 template <class E> |
|
663 struct nsTArray_CopyChooser { |
|
664 typedef nsTArray_CopyWithMemutils Type; |
|
665 }; |
|
666 |
|
667 // |
|
668 // Some classes require constructors/destructors to be called, so they are |
|
669 // specialized here. |
|
670 // |
|
671 template <class E> |
|
672 struct nsTArray_CopyChooser<JS::Heap<E> > { |
|
673 typedef nsTArray_CopyWithConstructors<JS::Heap<E> > Type; |
|
674 }; |
|
675 |
|
676 template<> |
|
677 struct nsTArray_CopyChooser<nsRegion> { |
|
678 typedef nsTArray_CopyWithConstructors<nsRegion> Type; |
|
679 }; |
|
680 |
|
681 template<> |
|
682 struct nsTArray_CopyChooser<nsIntRegion> { |
|
683 typedef nsTArray_CopyWithConstructors<nsIntRegion> Type; |
|
684 }; |
|
685 |
|
686 // |
|
687 // Base class for nsTArray_Impl that is templated on element type and derived |
|
688 // nsTArray_Impl class, to allow extra conversions to be added for specific |
|
689 // types. |
|
690 // |
|
691 template <class E, class Derived> |
|
692 struct nsTArray_TypedBase : public nsTArray_SafeElementAtHelper<E, Derived> {}; |
|
693 |
|
694 // |
|
695 // Specialization of nsTArray_TypedBase for arrays containing JS::Heap<E> |
|
696 // elements. |
|
697 // |
|
698 // These conversions are safe because JS::Heap<E> and E share the same |
|
699 // representation, and since the result of the conversions are const references |
|
700 // we won't miss any barriers. |
|
701 // |
|
702 // The static_cast is necessary to obtain the correct address for the derived |
|
703 // class since we are a base class used in multiple inheritance. |
|
704 // |
|
705 template <class E, class Derived> |
|
706 struct nsTArray_TypedBase<JS::Heap<E>, Derived> |
|
707 : public nsTArray_SafeElementAtHelper<JS::Heap<E>, Derived> |
|
708 { |
|
709 operator const nsTArray<E>& () { |
|
710 static_assert(sizeof(E) == sizeof(JS::Heap<E>), |
|
711 "JS::Heap<E> must be binary compatible with E."); |
|
712 Derived* self = static_cast<Derived*>(this); |
|
713 return *reinterpret_cast<nsTArray<E> *>(self); |
|
714 } |
|
715 |
|
716 operator const FallibleTArray<E>& () { |
|
717 Derived* self = static_cast<Derived*>(this); |
|
718 return *reinterpret_cast<FallibleTArray<E> *>(self); |
|
719 } |
|
720 }; |
|
721 |
|
722 |
|
723 // |
|
724 // nsTArray_Impl contains most of the guts supporting nsTArray, FallibleTArray, |
|
725 // nsAutoTArray, and AutoFallibleTArray. |
|
726 // |
|
727 // The only situation in which you might need to use nsTArray_Impl in your code |
|
728 // is if you're writing code which mutates a TArray which may or may not be |
|
729 // infallible. |
|
730 // |
|
731 // Code which merely reads from a TArray which may or may not be infallible can |
|
732 // simply cast the TArray to |const nsTArray&|; both fallible and infallible |
|
733 // TArrays can be cast to |const nsTArray&|. |
|
734 // |
|
735 template<class E, class Alloc> |
|
736 class nsTArray_Impl : public nsTArray_base<Alloc, typename nsTArray_CopyChooser<E>::Type>, |
|
737 public nsTArray_TypedBase<E, nsTArray_Impl<E, Alloc> > |
|
738 { |
|
739 public: |
|
740 typedef typename nsTArray_CopyChooser<E>::Type copy_type; |
|
741 typedef nsTArray_base<Alloc, copy_type> base_type; |
|
742 typedef typename base_type::size_type size_type; |
|
743 typedef typename base_type::index_type index_type; |
|
744 typedef E elem_type; |
|
745 typedef nsTArray_Impl<E, Alloc> self_type; |
|
746 typedef nsTArrayElementTraits<E> elem_traits; |
|
747 typedef nsTArray_SafeElementAtHelper<E, self_type> safeelementat_helper_type; |
|
748 |
|
749 using safeelementat_helper_type::SafeElementAt; |
|
750 using base_type::EmptyHdr; |
|
751 |
|
752 // A special value that is used to indicate an invalid or unknown index |
|
753 // into the array. |
|
754 enum { |
|
755 NoIndex = index_type(-1) |
|
756 }; |
|
757 |
|
758 using base_type::Length; |
|
759 |
|
760 // |
|
761 // Finalization method |
|
762 // |
|
763 |
|
764 ~nsTArray_Impl() { Clear(); } |
|
765 |
|
766 // |
|
767 // Initialization methods |
|
768 // |
|
769 |
|
770 nsTArray_Impl() {} |
|
771 |
|
772 // Initialize this array and pre-allocate some number of elements. |
|
773 explicit nsTArray_Impl(size_type capacity) { |
|
774 SetCapacity(capacity); |
|
775 } |
|
776 |
|
777 // The array's copy-constructor performs a 'deep' copy of the given array. |
|
778 // @param other The array object to copy. |
|
779 // |
|
780 // It's very important that we declare this method as taking |const |
|
781 // self_type&| as opposed to taking |const nsTArray_Impl<E, OtherAlloc>| for |
|
782 // an arbitrary OtherAlloc. |
|
783 // |
|
784 // If we don't declare a constructor taking |const self_type&|, C++ generates |
|
785 // a copy-constructor for this class which merely copies the object's |
|
786 // members, which is obviously wrong. |
|
787 // |
|
788 // You can pass an nsTArray_Impl<E, OtherAlloc> to this method because |
|
789 // nsTArray_Impl<E, X> can be cast to const nsTArray_Impl<E, Y>&. So the |
|
790 // effect on the API is the same as if we'd declared this method as taking |
|
791 // |const nsTArray_Impl<E, OtherAlloc>&|. |
|
792 explicit nsTArray_Impl(const self_type& other) { |
|
793 AppendElements(other); |
|
794 } |
|
795 |
|
796 // Allow converting to a const array with a different kind of allocator, |
|
797 // Since the allocator doesn't matter for const arrays |
|
798 template<typename Allocator> |
|
799 operator const nsTArray_Impl<E, Allocator>&() const { |
|
800 return *reinterpret_cast<const nsTArray_Impl<E, Allocator>*>(this); |
|
801 } |
|
802 // And we have to do this for our subclasses too |
|
803 operator const nsTArray<E>&() const { |
|
804 return *reinterpret_cast<const InfallibleTArray<E>*>(this); |
|
805 } |
|
806 operator const FallibleTArray<E>&() const { |
|
807 return *reinterpret_cast<const FallibleTArray<E>*>(this); |
|
808 } |
|
809 |
|
810 // The array's assignment operator performs a 'deep' copy of the given |
|
811 // array. It is optimized to reuse existing storage if possible. |
|
812 // @param other The array object to copy. |
|
813 self_type& operator=(const self_type& other) { |
|
814 ReplaceElementsAt(0, Length(), other.Elements(), other.Length()); |
|
815 return *this; |
|
816 } |
|
817 |
|
818 // Return true if this array has the same length and the same |
|
819 // elements as |other|. |
|
820 template<typename Allocator> |
|
821 bool operator==(const nsTArray_Impl<E, Allocator>& other) const { |
|
822 size_type len = Length(); |
|
823 if (len != other.Length()) |
|
824 return false; |
|
825 |
|
826 // XXX std::equal would be as fast or faster here |
|
827 for (index_type i = 0; i < len; ++i) |
|
828 if (!(operator[](i) == other[i])) |
|
829 return false; |
|
830 |
|
831 return true; |
|
832 } |
|
833 |
|
834 // Return true if this array does not have the same length and the same |
|
835 // elements as |other|. |
|
836 bool operator!=(const self_type& other) const { |
|
837 return !operator==(other); |
|
838 } |
|
839 |
|
840 template<typename Allocator> |
|
841 self_type& operator=(const nsTArray_Impl<E, Allocator>& other) { |
|
842 ReplaceElementsAt(0, Length(), other.Elements(), other.Length()); |
|
843 return *this; |
|
844 } |
|
845 |
|
846 // @return The amount of memory used by this nsTArray_Impl, excluding |
|
847 // sizeof(*this). |
|
848 size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { |
|
849 if (this->UsesAutoArrayBuffer() || Hdr() == EmptyHdr()) |
|
850 return 0; |
|
851 return mallocSizeOf(this->Hdr()); |
|
852 } |
|
853 |
|
854 // @return The amount of memory used by this nsTArray_Impl, including |
|
855 // sizeof(*this). |
|
856 size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { |
|
857 return mallocSizeOf(this) + SizeOfExcludingThis(mallocSizeOf); |
|
858 } |
|
859 |
|
860 // |
|
861 // Accessor methods |
|
862 // |
|
863 |
|
864 // This method provides direct access to the array elements. |
|
865 // @return A pointer to the first element of the array. If the array is |
|
866 // empty, then this pointer must not be dereferenced. |
|
867 elem_type* Elements() { |
|
868 return reinterpret_cast<elem_type *>(Hdr() + 1); |
|
869 } |
|
870 |
|
871 // This method provides direct, readonly access to the array elements. |
|
872 // @return A pointer to the first element of the array. If the array is |
|
873 // empty, then this pointer must not be dereferenced. |
|
874 const elem_type* Elements() const { |
|
875 return reinterpret_cast<const elem_type *>(Hdr() + 1); |
|
876 } |
|
877 |
|
878 // This method provides direct access to the i'th element of the array. |
|
879 // The given index must be within the array bounds. |
|
880 // @param i The index of an element in the array. |
|
881 // @return A reference to the i'th element of the array. |
|
882 elem_type& ElementAt(index_type i) { |
|
883 MOZ_ASSERT(i < Length(), "invalid array index"); |
|
884 return Elements()[i]; |
|
885 } |
|
886 |
|
887 // This method provides direct, readonly access to the i'th element of the |
|
888 // array. The given index must be within the array bounds. |
|
889 // @param i The index of an element in the array. |
|
890 // @return A const reference to the i'th element of the array. |
|
891 const elem_type& ElementAt(index_type i) const { |
|
892 MOZ_ASSERT(i < Length(), "invalid array index"); |
|
893 return Elements()[i]; |
|
894 } |
|
895 |
|
896 // This method provides direct access to the i'th element of the array in |
|
897 // a bounds safe manner. If the requested index is out of bounds the |
|
898 // provided default value is returned. |
|
899 // @param i The index of an element in the array. |
|
900 // @param def The value to return if the index is out of bounds. |
|
901 elem_type& SafeElementAt(index_type i, elem_type& def) { |
|
902 return i < Length() ? Elements()[i] : def; |
|
903 } |
|
904 |
|
905 // This method provides direct access to the i'th element of the array in |
|
906 // a bounds safe manner. If the requested index is out of bounds the |
|
907 // provided default value is returned. |
|
908 // @param i The index of an element in the array. |
|
909 // @param def The value to return if the index is out of bounds. |
|
910 const elem_type& SafeElementAt(index_type i, const elem_type& def) const { |
|
911 return i < Length() ? Elements()[i] : def; |
|
912 } |
|
913 |
|
914 // Shorthand for ElementAt(i) |
|
915 elem_type& operator[](index_type i) { |
|
916 return ElementAt(i); |
|
917 } |
|
918 |
|
919 // Shorthand for ElementAt(i) |
|
920 const elem_type& operator[](index_type i) const { |
|
921 return ElementAt(i); |
|
922 } |
|
923 |
|
924 // Shorthand for ElementAt(length - 1) |
|
925 elem_type& LastElement() { |
|
926 return ElementAt(Length() - 1); |
|
927 } |
|
928 |
|
929 // Shorthand for ElementAt(length - 1) |
|
930 const elem_type& LastElement() const { |
|
931 return ElementAt(Length() - 1); |
|
932 } |
|
933 |
|
934 // Shorthand for SafeElementAt(length - 1, def) |
|
935 elem_type& SafeLastElement(elem_type& def) { |
|
936 return SafeElementAt(Length() - 1, def); |
|
937 } |
|
938 |
|
939 // Shorthand for SafeElementAt(length - 1, def) |
|
940 const elem_type& SafeLastElement(const elem_type& def) const { |
|
941 return SafeElementAt(Length() - 1, def); |
|
942 } |
|
943 |
|
944 // |
|
945 // Search methods |
|
946 // |
|
947 |
|
948 // This method searches for the first element in this array that is equal |
|
949 // to the given element. |
|
950 // @param item The item to search for. |
|
951 // @param comp The Comparator used to determine element equality. |
|
952 // @return true if the element was found. |
|
953 template<class Item, class Comparator> |
|
954 bool Contains(const Item& item, const Comparator& comp) const { |
|
955 return IndexOf(item, 0, comp) != NoIndex; |
|
956 } |
|
957 |
|
958 // This method searches for the first element in this array that is equal |
|
959 // to the given element. This method assumes that 'operator==' is defined |
|
960 // for elem_type. |
|
961 // @param item The item to search for. |
|
962 // @return true if the element was found. |
|
963 template<class Item> |
|
964 bool Contains(const Item& item) const { |
|
965 return IndexOf(item) != NoIndex; |
|
966 } |
|
967 |
|
968 // This method searches for the offset of the first element in this |
|
969 // array that is equal to the given element. |
|
970 // @param item The item to search for. |
|
971 // @param start The index to start from. |
|
972 // @param comp The Comparator used to determine element equality. |
|
973 // @return The index of the found element or NoIndex if not found. |
|
974 template<class Item, class Comparator> |
|
975 index_type IndexOf(const Item& item, index_type start, |
|
976 const Comparator& comp) const { |
|
977 const elem_type* iter = Elements() + start, *end = Elements() + Length(); |
|
978 for (; iter != end; ++iter) { |
|
979 if (comp.Equals(*iter, item)) |
|
980 return index_type(iter - Elements()); |
|
981 } |
|
982 return NoIndex; |
|
983 } |
|
984 |
|
985 // This method searches for the offset of the first element in this |
|
986 // array that is equal to the given element. This method assumes |
|
987 // that 'operator==' is defined for elem_type. |
|
988 // @param item The item to search for. |
|
989 // @param start The index to start from. |
|
990 // @return The index of the found element or NoIndex if not found. |
|
991 template<class Item> |
|
992 index_type IndexOf(const Item& item, index_type start = 0) const { |
|
993 return IndexOf(item, start, nsDefaultComparator<elem_type, Item>()); |
|
994 } |
|
995 |
|
996 // This method searches for the offset of the last element in this |
|
997 // array that is equal to the given element. |
|
998 // @param item The item to search for. |
|
999 // @param start The index to start from. If greater than or equal to the |
|
1000 // length of the array, then the entire array is searched. |
|
1001 // @param comp The Comparator used to determine element equality. |
|
1002 // @return The index of the found element or NoIndex if not found. |
|
1003 template<class Item, class Comparator> |
|
1004 index_type LastIndexOf(const Item& item, index_type start, |
|
1005 const Comparator& comp) const { |
|
1006 size_type endOffset = start >= Length() ? Length() : start + 1; |
|
1007 const elem_type* end = Elements() - 1, *iter = end + endOffset; |
|
1008 for (; iter != end; --iter) { |
|
1009 if (comp.Equals(*iter, item)) |
|
1010 return index_type(iter - Elements()); |
|
1011 } |
|
1012 return NoIndex; |
|
1013 } |
|
1014 |
|
1015 // This method searches for the offset of the last element in this |
|
1016 // array that is equal to the given element. This method assumes |
|
1017 // that 'operator==' is defined for elem_type. |
|
1018 // @param item The item to search for. |
|
1019 // @param start The index to start from. If greater than or equal to the |
|
1020 // length of the array, then the entire array is searched. |
|
1021 // @return The index of the found element or NoIndex if not found. |
|
1022 template<class Item> |
|
1023 index_type LastIndexOf(const Item& item, |
|
1024 index_type start = NoIndex) const { |
|
1025 return LastIndexOf(item, start, nsDefaultComparator<elem_type, Item>()); |
|
1026 } |
|
1027 |
|
1028 // This method searches for the offset for the element in this array |
|
1029 // that is equal to the given element. The array is assumed to be sorted. |
|
1030 // @param item The item to search for. |
|
1031 // @param comp The Comparator used. |
|
1032 // @return The index of the found element or NoIndex if not found. |
|
1033 template<class Item, class Comparator> |
|
1034 index_type BinaryIndexOf(const Item& item, const Comparator& comp) const { |
|
1035 index_type low = 0, high = Length(); |
|
1036 while (high > low) { |
|
1037 index_type mid = (high + low) >> 1; |
|
1038 if (comp.Equals(ElementAt(mid), item)) |
|
1039 return mid; |
|
1040 if (comp.LessThan(ElementAt(mid), item)) |
|
1041 low = mid + 1; |
|
1042 else |
|
1043 high = mid; |
|
1044 } |
|
1045 return NoIndex; |
|
1046 } |
|
1047 |
|
1048 // This method searches for the offset for the element in this array |
|
1049 // that is equal to the given element. The array is assumed to be sorted. |
|
1050 // This method assumes that 'operator==' and 'operator<' are defined. |
|
1051 // @param item The item to search for. |
|
1052 // @return The index of the found element or NoIndex if not found. |
|
1053 template<class Item> |
|
1054 index_type BinaryIndexOf(const Item& item) const { |
|
1055 return BinaryIndexOf(item, nsDefaultComparator<elem_type, Item>()); |
|
1056 } |
|
1057 |
|
1058 // |
|
1059 // Mutation methods |
|
1060 // |
|
1061 // This method call the destructor on each element of the array, empties it, |
|
1062 // but does not shrink the array's capacity. |
|
1063 // See also SetLengthAndRetainStorage. |
|
1064 // Make sure to call Compact() if needed to avoid keeping a huge array |
|
1065 // around. |
|
1066 void ClearAndRetainStorage() { |
|
1067 if (base_type::mHdr == EmptyHdr()) { |
|
1068 return; |
|
1069 } |
|
1070 |
|
1071 DestructRange(0, Length()); |
|
1072 base_type::mHdr->mLength = 0; |
|
1073 } |
|
1074 |
|
1075 // This method modifies the length of the array, but unlike SetLength |
|
1076 // it doesn't deallocate/reallocate the current internal storage. |
|
1077 // The new length MUST be shorter than or equal to the current capacity. |
|
1078 // If the new length is larger than the existing length of the array, |
|
1079 // then new elements will be constructed using elem_type's default |
|
1080 // constructor. If shorter, elements will be destructed and removed. |
|
1081 // See also ClearAndRetainStorage. |
|
1082 // @param newLen The desired length of this array. |
|
1083 void SetLengthAndRetainStorage(size_type newLen) { |
|
1084 MOZ_ASSERT(newLen <= base_type::Capacity()); |
|
1085 size_type oldLen = Length(); |
|
1086 if (newLen > oldLen) { |
|
1087 InsertElementsAt(oldLen, newLen - oldLen); |
|
1088 return; |
|
1089 } |
|
1090 if (newLen < oldLen) { |
|
1091 DestructRange(newLen, oldLen - newLen); |
|
1092 base_type::mHdr->mLength = newLen; |
|
1093 } |
|
1094 } |
|
1095 |
|
1096 // This method replaces a range of elements in this array. |
|
1097 // @param start The starting index of the elements to replace. |
|
1098 // @param count The number of elements to replace. This may be zero to |
|
1099 // insert elements without removing any existing elements. |
|
1100 // @param array The values to copy into this array. Must be non-null, |
|
1101 // and these elements must not already exist in the array |
|
1102 // being modified. |
|
1103 // @param arrayLen The number of values to copy into this array. |
|
1104 // @return A pointer to the new elements in the array, or null if |
|
1105 // the operation failed due to insufficient memory. |
|
1106 template<class Item> |
|
1107 elem_type *ReplaceElementsAt(index_type start, size_type count, |
|
1108 const Item* array, size_type arrayLen) { |
|
1109 // Adjust memory allocation up-front to catch errors. |
|
1110 if (!Alloc::Successful(this->EnsureCapacity(Length() + arrayLen - count, sizeof(elem_type)))) |
|
1111 return nullptr; |
|
1112 DestructRange(start, count); |
|
1113 this->ShiftData(start, count, arrayLen, sizeof(elem_type), MOZ_ALIGNOF(elem_type)); |
|
1114 AssignRange(start, arrayLen, array); |
|
1115 return Elements() + start; |
|
1116 } |
|
1117 |
|
1118 // A variation on the ReplaceElementsAt method defined above. |
|
1119 template<class Item> |
|
1120 elem_type *ReplaceElementsAt(index_type start, size_type count, |
|
1121 const nsTArray<Item>& array) { |
|
1122 return ReplaceElementsAt(start, count, array.Elements(), array.Length()); |
|
1123 } |
|
1124 |
|
1125 // A variation on the ReplaceElementsAt method defined above. |
|
1126 template<class Item> |
|
1127 elem_type *ReplaceElementsAt(index_type start, size_type count, |
|
1128 const Item& item) { |
|
1129 return ReplaceElementsAt(start, count, &item, 1); |
|
1130 } |
|
1131 |
|
1132 // A variation on the ReplaceElementsAt method defined above. |
|
1133 template<class Item> |
|
1134 elem_type *ReplaceElementAt(index_type index, const Item& item) { |
|
1135 return ReplaceElementsAt(index, 1, &item, 1); |
|
1136 } |
|
1137 |
|
1138 // A variation on the ReplaceElementsAt method defined above. |
|
1139 template<class Item> |
|
1140 elem_type *InsertElementsAt(index_type index, const Item* array, |
|
1141 size_type arrayLen) { |
|
1142 return ReplaceElementsAt(index, 0, array, arrayLen); |
|
1143 } |
|
1144 |
|
1145 // A variation on the ReplaceElementsAt method defined above. |
|
1146 template<class Item, class Allocator> |
|
1147 elem_type *InsertElementsAt(index_type index, const nsTArray_Impl<Item, Allocator>& array) { |
|
1148 return ReplaceElementsAt(index, 0, array.Elements(), array.Length()); |
|
1149 } |
|
1150 |
|
1151 // A variation on the ReplaceElementsAt method defined above. |
|
1152 template<class Item> |
|
1153 elem_type *InsertElementAt(index_type index, const Item& item) { |
|
1154 return ReplaceElementsAt(index, 0, &item, 1); |
|
1155 } |
|
1156 |
|
1157 // Insert a new element without copy-constructing. This is useful to avoid |
|
1158 // temporaries. |
|
1159 // @return A pointer to the newly inserted element, or null on OOM. |
|
1160 elem_type* InsertElementAt(index_type index) { |
|
1161 if (!Alloc::Successful(this->EnsureCapacity(Length() + 1, sizeof(elem_type)))) |
|
1162 return nullptr; |
|
1163 this->ShiftData(index, 0, 1, sizeof(elem_type), MOZ_ALIGNOF(elem_type)); |
|
1164 elem_type *elem = Elements() + index; |
|
1165 elem_traits::Construct(elem); |
|
1166 return elem; |
|
1167 } |
|
1168 |
|
1169 // This method searches for the smallest index of an element that is strictly |
|
1170 // greater than |item|. If |item| is inserted at this index, the array will |
|
1171 // remain sorted and |item| would come after all elements that are equal to |
|
1172 // it. If |item| is greater than or equal to all elements in the array, the |
|
1173 // array length is returned. |
|
1174 // |
|
1175 // Note that consumers who want to know whether there are existing items equal |
|
1176 // to |item| in the array can just check that the return value here is > 0 and |
|
1177 // indexing into the previous slot gives something equal to |item|. |
|
1178 // |
|
1179 // |
|
1180 // @param item The item to search for. |
|
1181 // @param comp The Comparator used. |
|
1182 // @return The index of greatest element <= to |item| |
|
1183 // @precondition The array is sorted |
|
1184 template<class Item, class Comparator> |
|
1185 index_type |
|
1186 IndexOfFirstElementGt(const Item& item, |
|
1187 const Comparator& comp) const { |
|
1188 // invariant: low <= [idx] <= high |
|
1189 index_type low = 0, high = Length(); |
|
1190 while (high > low) { |
|
1191 index_type mid = (high + low) >> 1; |
|
1192 // Comparators are not required to provide a LessThan(Item&, elem_type), |
|
1193 // so we can't do comp.LessThan(item, ElementAt(mid)). |
|
1194 if (comp.LessThan(ElementAt(mid), item) || |
|
1195 comp.Equals(ElementAt(mid), item)) { |
|
1196 // item >= ElementAt(mid), so our desired index is at least mid+1. |
|
1197 low = mid + 1; |
|
1198 } else { |
|
1199 // item < ElementAt(mid). Our desired index is therefore at most mid. |
|
1200 high = mid; |
|
1201 } |
|
1202 } |
|
1203 MOZ_ASSERT(high == low); |
|
1204 return low; |
|
1205 } |
|
1206 |
|
1207 // A variation on the IndexOfFirstElementGt method defined above. |
|
1208 template<class Item> |
|
1209 index_type |
|
1210 IndexOfFirstElementGt(const Item& item) const { |
|
1211 return IndexOfFirstElementGt(item, nsDefaultComparator<elem_type, Item>()); |
|
1212 } |
|
1213 |
|
1214 // Inserts |item| at such an index to guarantee that if the array |
|
1215 // was previously sorted, it will remain sorted after this |
|
1216 // insertion. |
|
1217 template<class Item, class Comparator> |
|
1218 elem_type *InsertElementSorted(const Item& item, const Comparator& comp) { |
|
1219 index_type index = IndexOfFirstElementGt(item, comp); |
|
1220 return InsertElementAt(index, item); |
|
1221 } |
|
1222 |
|
1223 // A variation on the InsertElementSorted method defined above. |
|
1224 template<class Item> |
|
1225 elem_type *InsertElementSorted(const Item& item) { |
|
1226 return InsertElementSorted(item, nsDefaultComparator<elem_type, Item>()); |
|
1227 } |
|
1228 |
|
1229 // This method appends elements to the end of this array. |
|
1230 // @param array The elements to append to this array. |
|
1231 // @param arrayLen The number of elements to append to this array. |
|
1232 // @return A pointer to the new elements in the array, or null if |
|
1233 // the operation failed due to insufficient memory. |
|
1234 template<class Item> |
|
1235 elem_type *AppendElements(const Item* array, size_type arrayLen) { |
|
1236 if (!Alloc::Successful(this->EnsureCapacity(Length() + arrayLen, sizeof(elem_type)))) |
|
1237 return nullptr; |
|
1238 index_type len = Length(); |
|
1239 AssignRange(len, arrayLen, array); |
|
1240 this->IncrementLength(arrayLen); |
|
1241 return Elements() + len; |
|
1242 } |
|
1243 |
|
1244 // A variation on the AppendElements method defined above. |
|
1245 template<class Item, class Allocator> |
|
1246 elem_type *AppendElements(const nsTArray_Impl<Item, Allocator>& array) { |
|
1247 return AppendElements(array.Elements(), array.Length()); |
|
1248 } |
|
1249 |
|
1250 // A variation on the AppendElements method defined above. |
|
1251 template<class Item> |
|
1252 elem_type *AppendElement(const Item& item) { |
|
1253 return AppendElements(&item, 1); |
|
1254 } |
|
1255 |
|
1256 // Append new elements without copy-constructing. This is useful to avoid |
|
1257 // temporaries. |
|
1258 // @return A pointer to the newly appended elements, or null on OOM. |
|
1259 elem_type *AppendElements(size_type count) { |
|
1260 if (!Alloc::Successful(this->EnsureCapacity(Length() + count, sizeof(elem_type)))) |
|
1261 return nullptr; |
|
1262 elem_type *elems = Elements() + Length(); |
|
1263 size_type i; |
|
1264 for (i = 0; i < count; ++i) { |
|
1265 elem_traits::Construct(elems + i); |
|
1266 } |
|
1267 this->IncrementLength(count); |
|
1268 return elems; |
|
1269 } |
|
1270 |
|
1271 // Append a new element without copy-constructing. This is useful to avoid |
|
1272 // temporaries. |
|
1273 // @return A pointer to the newly appended element, or null on OOM. |
|
1274 elem_type *AppendElement() { |
|
1275 return AppendElements(1); |
|
1276 } |
|
1277 |
|
1278 // Move all elements from another array to the end of this array without |
|
1279 // calling copy constructors or destructors. |
|
1280 // @return A pointer to the newly appended elements, or null on OOM. |
|
1281 template<class Item, class Allocator> |
|
1282 elem_type *MoveElementsFrom(nsTArray_Impl<Item, Allocator>& array) { |
|
1283 MOZ_ASSERT(&array != this, "argument must be different array"); |
|
1284 index_type len = Length(); |
|
1285 index_type otherLen = array.Length(); |
|
1286 if (!Alloc::Successful(this->EnsureCapacity(len + otherLen, sizeof(elem_type)))) |
|
1287 return nullptr; |
|
1288 copy_type::CopyElements(Elements() + len, array.Elements(), otherLen, sizeof(elem_type)); |
|
1289 this->IncrementLength(otherLen); |
|
1290 array.ShiftData(0, otherLen, 0, sizeof(elem_type), MOZ_ALIGNOF(elem_type)); |
|
1291 return Elements() + len; |
|
1292 } |
|
1293 |
|
1294 // This method removes a range of elements from this array. |
|
1295 // @param start The starting index of the elements to remove. |
|
1296 // @param count The number of elements to remove. |
|
1297 void RemoveElementsAt(index_type start, size_type count) { |
|
1298 MOZ_ASSERT(count == 0 || start < Length(), "Invalid start index"); |
|
1299 MOZ_ASSERT(start + count <= Length(), "Invalid length"); |
|
1300 // Check that the previous assert didn't overflow |
|
1301 MOZ_ASSERT(start <= start + count, "Start index plus length overflows"); |
|
1302 DestructRange(start, count); |
|
1303 this->ShiftData(start, count, 0, sizeof(elem_type), MOZ_ALIGNOF(elem_type)); |
|
1304 } |
|
1305 |
|
1306 // A variation on the RemoveElementsAt method defined above. |
|
1307 void RemoveElementAt(index_type index) { |
|
1308 RemoveElementsAt(index, 1); |
|
1309 } |
|
1310 |
|
1311 // A variation on the RemoveElementsAt method defined above. |
|
1312 void Clear() { |
|
1313 RemoveElementsAt(0, Length()); |
|
1314 } |
|
1315 |
|
1316 // This helper function combines IndexOf with RemoveElementAt to "search |
|
1317 // and destroy" the first element that is equal to the given element. |
|
1318 // @param item The item to search for. |
|
1319 // @param comp The Comparator used to determine element equality. |
|
1320 // @return true if the element was found |
|
1321 template<class Item, class Comparator> |
|
1322 bool RemoveElement(const Item& item, const Comparator& comp) { |
|
1323 index_type i = IndexOf(item, 0, comp); |
|
1324 if (i == NoIndex) |
|
1325 return false; |
|
1326 |
|
1327 RemoveElementAt(i); |
|
1328 return true; |
|
1329 } |
|
1330 |
|
1331 // A variation on the RemoveElement method defined above that assumes |
|
1332 // that 'operator==' is defined for elem_type. |
|
1333 template<class Item> |
|
1334 bool RemoveElement(const Item& item) { |
|
1335 return RemoveElement(item, nsDefaultComparator<elem_type, Item>()); |
|
1336 } |
|
1337 |
|
1338 // This helper function combines IndexOfFirstElementGt with |
|
1339 // RemoveElementAt to "search and destroy" the last element that |
|
1340 // is equal to the given element. |
|
1341 // @param item The item to search for. |
|
1342 // @param comp The Comparator used to determine element equality. |
|
1343 // @return true if the element was found |
|
1344 template<class Item, class Comparator> |
|
1345 bool RemoveElementSorted(const Item& item, const Comparator& comp) { |
|
1346 index_type index = IndexOfFirstElementGt(item, comp); |
|
1347 if (index > 0 && comp.Equals(ElementAt(index - 1), item)) { |
|
1348 RemoveElementAt(index - 1); |
|
1349 return true; |
|
1350 } |
|
1351 return false; |
|
1352 } |
|
1353 |
|
1354 // A variation on the RemoveElementSorted method defined above. |
|
1355 template<class Item> |
|
1356 bool RemoveElementSorted(const Item& item) { |
|
1357 return RemoveElementSorted(item, nsDefaultComparator<elem_type, Item>()); |
|
1358 } |
|
1359 |
|
1360 // This method causes the elements contained in this array and the given |
|
1361 // array to be swapped. |
|
1362 template<class Allocator> |
|
1363 typename Alloc::ResultType |
|
1364 SwapElements(nsTArray_Impl<E, Allocator>& other) { |
|
1365 return Alloc::Result(this->SwapArrayElements(other, sizeof(elem_type), |
|
1366 MOZ_ALIGNOF(elem_type))); |
|
1367 } |
|
1368 |
|
1369 // |
|
1370 // Allocation |
|
1371 // |
|
1372 |
|
1373 // This method may increase the capacity of this array object by the |
|
1374 // specified amount. This method may be called in advance of several |
|
1375 // AppendElement operations to minimize heap re-allocations. This method |
|
1376 // will not reduce the number of elements in this array. |
|
1377 // @param capacity The desired capacity of this array. |
|
1378 // @return True if the operation succeeded; false if we ran out of memory |
|
1379 typename Alloc::ResultType SetCapacity(size_type capacity) { |
|
1380 return Alloc::Result(this->EnsureCapacity(capacity, sizeof(elem_type))); |
|
1381 } |
|
1382 |
|
1383 // This method modifies the length of the array. If the new length is |
|
1384 // larger than the existing length of the array, then new elements will be |
|
1385 // constructed using elem_type's default constructor. Otherwise, this call |
|
1386 // removes elements from the array (see also RemoveElementsAt). |
|
1387 // @param newLen The desired length of this array. |
|
1388 // @return True if the operation succeeded; false otherwise. |
|
1389 // See also TruncateLength if the new length is guaranteed to be |
|
1390 // smaller than the old. |
|
1391 typename Alloc::ResultType SetLength(size_type newLen) { |
|
1392 size_type oldLen = Length(); |
|
1393 if (newLen > oldLen) { |
|
1394 return Alloc::ConvertBoolToResultType(InsertElementsAt(oldLen, newLen - oldLen) != nullptr); |
|
1395 } |
|
1396 |
|
1397 TruncateLength(newLen); |
|
1398 return Alloc::ConvertBoolToResultType(true); |
|
1399 } |
|
1400 |
|
1401 // This method modifies the length of the array, but may only be |
|
1402 // called when the new length is shorter than the old. It can |
|
1403 // therefore be called when elem_type has no default constructor, |
|
1404 // unlike SetLength. It removes elements from the array (see also |
|
1405 // RemoveElementsAt). |
|
1406 // @param newLen The desired length of this array. |
|
1407 void TruncateLength(size_type newLen) { |
|
1408 size_type oldLen = Length(); |
|
1409 NS_ABORT_IF_FALSE(newLen <= oldLen, |
|
1410 "caller should use SetLength instead"); |
|
1411 RemoveElementsAt(newLen, oldLen - newLen); |
|
1412 } |
|
1413 |
|
1414 // This method ensures that the array has length at least the given |
|
1415 // length. If the current length is shorter than the given length, |
|
1416 // then new elements will be constructed using elem_type's default |
|
1417 // constructor. |
|
1418 // @param minLen The desired minimum length of this array. |
|
1419 // @return True if the operation succeeded; false otherwise. |
|
1420 typename Alloc::ResultType EnsureLengthAtLeast(size_type minLen) { |
|
1421 size_type oldLen = Length(); |
|
1422 if (minLen > oldLen) { |
|
1423 return Alloc::ConvertBoolToResultType(!!InsertElementsAt(oldLen, minLen - oldLen)); |
|
1424 } |
|
1425 return Alloc::ConvertBoolToResultType(true); |
|
1426 } |
|
1427 |
|
1428 // This method inserts elements into the array, constructing |
|
1429 // them using elem_type's default constructor. |
|
1430 // @param index the place to insert the new elements. This must be no |
|
1431 // greater than the current length of the array. |
|
1432 // @param count the number of elements to insert |
|
1433 elem_type *InsertElementsAt(index_type index, size_type count) { |
|
1434 if (!base_type::InsertSlotsAt(index, count, sizeof(elem_type), MOZ_ALIGNOF(elem_type))) { |
|
1435 return nullptr; |
|
1436 } |
|
1437 |
|
1438 // Initialize the extra array elements |
|
1439 elem_type *iter = Elements() + index, *end = iter + count; |
|
1440 for (; iter != end; ++iter) { |
|
1441 elem_traits::Construct(iter); |
|
1442 } |
|
1443 |
|
1444 return Elements() + index; |
|
1445 } |
|
1446 |
|
1447 // This method inserts elements into the array, constructing them |
|
1448 // elem_type's copy constructor (or whatever one-arg constructor |
|
1449 // happens to match the Item type). |
|
1450 // @param index the place to insert the new elements. This must be no |
|
1451 // greater than the current length of the array. |
|
1452 // @param count the number of elements to insert. |
|
1453 // @param item the value to use when constructing the new elements. |
|
1454 template<class Item> |
|
1455 elem_type *InsertElementsAt(index_type index, size_type count, |
|
1456 const Item& item) { |
|
1457 if (!base_type::InsertSlotsAt(index, count, sizeof(elem_type), MOZ_ALIGNOF(elem_type))) { |
|
1458 return nullptr; |
|
1459 } |
|
1460 |
|
1461 // Initialize the extra array elements |
|
1462 elem_type *iter = Elements() + index, *end = iter + count; |
|
1463 for (; iter != end; ++iter) { |
|
1464 elem_traits::Construct(iter, item); |
|
1465 } |
|
1466 |
|
1467 return Elements() + index; |
|
1468 } |
|
1469 |
|
1470 // This method may be called to minimize the memory used by this array. |
|
1471 void Compact() { |
|
1472 ShrinkCapacity(sizeof(elem_type), MOZ_ALIGNOF(elem_type)); |
|
1473 } |
|
1474 |
|
1475 // |
|
1476 // Sorting |
|
1477 // |
|
1478 |
|
1479 // This function is meant to be used with the NS_QuickSort function. It |
|
1480 // maps the callback API expected by NS_QuickSort to the Comparator API |
|
1481 // used by nsTArray_Impl. See nsTArray_Impl::Sort. |
|
1482 template<class Comparator> |
|
1483 static int Compare(const void* e1, const void* e2, void *data) { |
|
1484 const Comparator* c = reinterpret_cast<const Comparator*>(data); |
|
1485 const elem_type* a = static_cast<const elem_type*>(e1); |
|
1486 const elem_type* b = static_cast<const elem_type*>(e2); |
|
1487 return c->LessThan(*a, *b) ? -1 : (c->Equals(*a, *b) ? 0 : 1); |
|
1488 } |
|
1489 |
|
1490 // This method sorts the elements of the array. It uses the LessThan |
|
1491 // method defined on the given Comparator object to collate elements. |
|
1492 // @param comp The Comparator used to collate elements. |
|
1493 template<class Comparator> |
|
1494 void Sort(const Comparator& comp) { |
|
1495 NS_QuickSort(Elements(), Length(), sizeof(elem_type), |
|
1496 Compare<Comparator>, const_cast<Comparator*>(&comp)); |
|
1497 } |
|
1498 |
|
1499 // A variation on the Sort method defined above that assumes that |
|
1500 // 'operator<' is defined for elem_type. |
|
1501 void Sort() { |
|
1502 Sort(nsDefaultComparator<elem_type, elem_type>()); |
|
1503 } |
|
1504 |
|
1505 // |
|
1506 // Binary Heap |
|
1507 // |
|
1508 |
|
1509 // Sorts the array into a binary heap. |
|
1510 // @param comp The Comparator used to create the heap |
|
1511 template<class Comparator> |
|
1512 void MakeHeap(const Comparator& comp) { |
|
1513 if (!Length()) { |
|
1514 return; |
|
1515 } |
|
1516 index_type index = (Length() - 1) / 2; |
|
1517 do { |
|
1518 SiftDown(index, comp); |
|
1519 } while (index--); |
|
1520 } |
|
1521 |
|
1522 // A variation on the MakeHeap method defined above. |
|
1523 void MakeHeap() { |
|
1524 MakeHeap(nsDefaultComparator<elem_type, elem_type>()); |
|
1525 } |
|
1526 |
|
1527 // Adds an element to the heap |
|
1528 // @param item The item to add |
|
1529 // @param comp The Comparator used to sift-up the item |
|
1530 template<class Item, class Comparator> |
|
1531 elem_type *PushHeap(const Item& item, const Comparator& comp) { |
|
1532 if (!base_type::InsertSlotsAt(Length(), 1, sizeof(elem_type), MOZ_ALIGNOF(elem_type))) { |
|
1533 return nullptr; |
|
1534 } |
|
1535 // Sift up the new node |
|
1536 elem_type *elem = Elements(); |
|
1537 index_type index = Length() - 1; |
|
1538 index_type parent_index = (index - 1) / 2; |
|
1539 while (index && comp.LessThan(elem[parent_index], item)) { |
|
1540 elem[index] = elem[parent_index]; |
|
1541 index = parent_index; |
|
1542 parent_index = (index - 1) / 2; |
|
1543 } |
|
1544 elem[index] = item; |
|
1545 return &elem[index]; |
|
1546 } |
|
1547 |
|
1548 // A variation on the PushHeap method defined above. |
|
1549 template<class Item> |
|
1550 elem_type *PushHeap(const Item& item) { |
|
1551 return PushHeap(item, nsDefaultComparator<elem_type, Item>()); |
|
1552 } |
|
1553 |
|
1554 // Delete the root of the heap and restore the heap |
|
1555 // @param comp The Comparator used to restore the heap |
|
1556 template<class Comparator> |
|
1557 void PopHeap(const Comparator& comp) { |
|
1558 if (!Length()) { |
|
1559 return; |
|
1560 } |
|
1561 index_type last_index = Length() - 1; |
|
1562 elem_type *elem = Elements(); |
|
1563 elem[0] = elem[last_index]; |
|
1564 TruncateLength(last_index); |
|
1565 if (Length()) { |
|
1566 SiftDown(0, comp); |
|
1567 } |
|
1568 } |
|
1569 |
|
1570 // A variation on the PopHeap method defined above. |
|
1571 void PopHeap() { |
|
1572 PopHeap(nsDefaultComparator<elem_type, elem_type>()); |
|
1573 } |
|
1574 |
|
1575 protected: |
|
1576 using base_type::Hdr; |
|
1577 using base_type::ShrinkCapacity; |
|
1578 |
|
1579 // This method invokes elem_type's destructor on a range of elements. |
|
1580 // @param start The index of the first element to destroy. |
|
1581 // @param count The number of elements to destroy. |
|
1582 void DestructRange(index_type start, size_type count) { |
|
1583 elem_type *iter = Elements() + start, *end = iter + count; |
|
1584 for (; iter != end; ++iter) { |
|
1585 elem_traits::Destruct(iter); |
|
1586 } |
|
1587 } |
|
1588 |
|
1589 // This method invokes elem_type's copy-constructor on a range of elements. |
|
1590 // @param start The index of the first element to construct. |
|
1591 // @param count The number of elements to construct. |
|
1592 // @param values The array of elements to copy. |
|
1593 template<class Item> |
|
1594 void AssignRange(index_type start, size_type count, |
|
1595 const Item *values) { |
|
1596 AssignRangeAlgorithm<mozilla::IsPod<Item>::value, |
|
1597 mozilla::IsSame<Item, elem_type>::value> |
|
1598 ::implementation(Elements(), start, count, values); |
|
1599 } |
|
1600 |
|
1601 // This method sifts an item down to its proper place in a binary heap |
|
1602 // @param index The index of the node to start sifting down from |
|
1603 // @param comp The Comparator used to sift down |
|
1604 template<class Comparator> |
|
1605 void SiftDown(index_type index, const Comparator& comp) { |
|
1606 elem_type *elem = Elements(); |
|
1607 elem_type item = elem[index]; |
|
1608 index_type end = Length() - 1; |
|
1609 while ((index * 2) < end) { |
|
1610 const index_type left = (index * 2) + 1; |
|
1611 const index_type right = (index * 2) + 2; |
|
1612 const index_type parent_index = index; |
|
1613 if (comp.LessThan(item, elem[left])) { |
|
1614 if (left < end && |
|
1615 comp.LessThan(elem[left], elem[right])) { |
|
1616 index = right; |
|
1617 } else { |
|
1618 index = left; |
|
1619 } |
|
1620 } else if (left < end && |
|
1621 comp.LessThan(item, elem[right])) { |
|
1622 index = right; |
|
1623 } else { |
|
1624 break; |
|
1625 } |
|
1626 elem[parent_index] = elem[index]; |
|
1627 } |
|
1628 elem[index] = item; |
|
1629 } |
|
1630 }; |
|
1631 |
|
1632 template <typename E, typename Alloc> |
|
1633 inline void |
|
1634 ImplCycleCollectionUnlink(nsTArray_Impl<E, Alloc>& aField) |
|
1635 { |
|
1636 aField.Clear(); |
|
1637 } |
|
1638 |
|
1639 template <typename E, typename Alloc> |
|
1640 inline void |
|
1641 ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, |
|
1642 nsTArray_Impl<E, Alloc>& aField, |
|
1643 const char* aName, |
|
1644 uint32_t aFlags = 0) |
|
1645 { |
|
1646 aFlags |= CycleCollectionEdgeNameArrayFlag; |
|
1647 uint32_t length = aField.Length(); |
|
1648 for (uint32_t i = 0; i < length; ++i) { |
|
1649 ImplCycleCollectionTraverse(aCallback, aField[i], aName, aFlags); |
|
1650 } |
|
1651 } |
|
1652 |
|
1653 // |
|
1654 // nsTArray is an infallible vector class. See the comment at the top of this |
|
1655 // file for more details. |
|
1656 // |
|
1657 template <class E> |
|
1658 class nsTArray : public nsTArray_Impl<E, nsTArrayInfallibleAllocator> |
|
1659 { |
|
1660 public: |
|
1661 typedef nsTArray_Impl<E, nsTArrayInfallibleAllocator> base_type; |
|
1662 typedef nsTArray<E> self_type; |
|
1663 typedef typename base_type::size_type size_type; |
|
1664 |
|
1665 nsTArray() {} |
|
1666 explicit nsTArray(size_type capacity) : base_type(capacity) {} |
|
1667 explicit nsTArray(const nsTArray& other) : base_type(other) {} |
|
1668 |
|
1669 template<class Allocator> |
|
1670 explicit nsTArray(const nsTArray_Impl<E, Allocator>& other) : base_type(other) {} |
|
1671 }; |
|
1672 |
|
1673 // |
|
1674 // FallibleTArray is a fallible vector class. |
|
1675 // |
|
1676 template <class E> |
|
1677 class FallibleTArray : public nsTArray_Impl<E, nsTArrayFallibleAllocator> |
|
1678 { |
|
1679 public: |
|
1680 typedef nsTArray_Impl<E, nsTArrayFallibleAllocator> base_type; |
|
1681 typedef FallibleTArray<E> self_type; |
|
1682 typedef typename base_type::size_type size_type; |
|
1683 |
|
1684 FallibleTArray() {} |
|
1685 explicit FallibleTArray(size_type capacity) : base_type(capacity) {} |
|
1686 explicit FallibleTArray(const FallibleTArray<E>& other) : base_type(other) {} |
|
1687 |
|
1688 template<class Allocator> |
|
1689 explicit FallibleTArray(const nsTArray_Impl<E, Allocator>& other) : base_type(other) {} |
|
1690 }; |
|
1691 |
|
1692 // |
|
1693 // nsAutoArrayBase is a base class for AutoFallibleTArray and nsAutoTArray. |
|
1694 // You shouldn't use this class directly. |
|
1695 // |
|
1696 template <class TArrayBase, uint32_t N> |
|
1697 class nsAutoArrayBase : public TArrayBase |
|
1698 { |
|
1699 public: |
|
1700 typedef nsAutoArrayBase<TArrayBase, N> self_type; |
|
1701 typedef TArrayBase base_type; |
|
1702 typedef typename base_type::Header Header; |
|
1703 typedef typename base_type::elem_type elem_type; |
|
1704 |
|
1705 template<typename Allocator> |
|
1706 self_type& operator=(const nsTArray_Impl<elem_type, Allocator>& other) { |
|
1707 base_type::operator=(other); |
|
1708 return *this; |
|
1709 } |
|
1710 |
|
1711 protected: |
|
1712 nsAutoArrayBase() { |
|
1713 Init(); |
|
1714 } |
|
1715 |
|
1716 // We need this constructor because nsAutoTArray and friends all have |
|
1717 // implicit copy-constructors. If we don't have this method, those |
|
1718 // copy-constructors will call nsAutoArrayBase's implicit copy-constructor, |
|
1719 // which won't call Init() and set up the auto buffer! |
|
1720 nsAutoArrayBase(const self_type &aOther) { |
|
1721 Init(); |
|
1722 this->AppendElements(aOther); |
|
1723 } |
|
1724 |
|
1725 private: |
|
1726 // nsTArray_base casts itself as an nsAutoArrayBase in order to get a pointer |
|
1727 // to mAutoBuf. |
|
1728 template<class Allocator, class Copier> |
|
1729 friend class nsTArray_base; |
|
1730 |
|
1731 void Init() { |
|
1732 static_assert(MOZ_ALIGNOF(elem_type) <= 8, |
|
1733 "can't handle alignments greater than 8, " |
|
1734 "see nsTArray_base::UsesAutoArrayBuffer()"); |
|
1735 // Temporary work around for VS2012 RC compiler crash |
|
1736 Header** phdr = base_type::PtrToHdr(); |
|
1737 *phdr = reinterpret_cast<Header*>(&mAutoBuf); |
|
1738 (*phdr)->mLength = 0; |
|
1739 (*phdr)->mCapacity = N; |
|
1740 (*phdr)->mIsAutoArray = 1; |
|
1741 |
|
1742 MOZ_ASSERT(base_type::GetAutoArrayBuffer(MOZ_ALIGNOF(elem_type)) == |
|
1743 reinterpret_cast<Header*>(&mAutoBuf), |
|
1744 "GetAutoArrayBuffer needs to be fixed"); |
|
1745 } |
|
1746 |
|
1747 // Declare mAutoBuf aligned to the maximum of the header's alignment and |
|
1748 // elem_type's alignment. We need to use a union rather than |
|
1749 // MOZ_ALIGNED_DECL because GCC is picky about what goes into |
|
1750 // __attribute__((aligned(foo))). |
|
1751 union { |
|
1752 char mAutoBuf[sizeof(nsTArrayHeader) + N * sizeof(elem_type)]; |
|
1753 // Do the max operation inline to ensure that it is a compile-time constant. |
|
1754 mozilla::AlignedElem<(MOZ_ALIGNOF(Header) > MOZ_ALIGNOF(elem_type)) |
|
1755 ? MOZ_ALIGNOF(Header) : MOZ_ALIGNOF(elem_type)> mAlign; |
|
1756 }; |
|
1757 }; |
|
1758 |
|
1759 // |
|
1760 // nsAutoTArray<E, N> is an infallible vector class with N elements of inline |
|
1761 // storage. If you try to store more than N elements inside an |
|
1762 // nsAutoTArray<E, N>, we'll call malloc() and store them all on the heap. |
|
1763 // |
|
1764 // Note that you can cast an nsAutoTArray<E, N> to |
|
1765 // |const AutoFallibleTArray<E, N>&|. |
|
1766 // |
|
1767 template<class E, uint32_t N> |
|
1768 class nsAutoTArray : public nsAutoArrayBase<nsTArray<E>, N> |
|
1769 { |
|
1770 typedef nsAutoTArray<E, N> self_type; |
|
1771 typedef nsAutoArrayBase<nsTArray<E>, N> Base; |
|
1772 |
|
1773 public: |
|
1774 nsAutoTArray() {} |
|
1775 |
|
1776 template<typename Allocator> |
|
1777 explicit nsAutoTArray(const nsTArray_Impl<E, Allocator>& other) { |
|
1778 Base::AppendElements(other); |
|
1779 } |
|
1780 |
|
1781 operator const AutoFallibleTArray<E, N>&() const { |
|
1782 return *reinterpret_cast<const AutoFallibleTArray<E, N>*>(this); |
|
1783 } |
|
1784 }; |
|
1785 |
|
1786 // |
|
1787 // AutoFallibleTArray<E, N> is a fallible vector class with N elements of |
|
1788 // inline storage. |
|
1789 // |
|
1790 template<class E, uint32_t N> |
|
1791 class AutoFallibleTArray : public nsAutoArrayBase<FallibleTArray<E>, N> |
|
1792 { |
|
1793 typedef AutoFallibleTArray<E, N> self_type; |
|
1794 typedef nsAutoArrayBase<FallibleTArray<E>, N> Base; |
|
1795 |
|
1796 public: |
|
1797 AutoFallibleTArray() {} |
|
1798 |
|
1799 template<typename Allocator> |
|
1800 explicit AutoFallibleTArray(const nsTArray_Impl<E, Allocator>& other) { |
|
1801 Base::AppendElements(other); |
|
1802 } |
|
1803 |
|
1804 operator const nsAutoTArray<E, N>&() const { |
|
1805 return *reinterpret_cast<const nsAutoTArray<E, N>*>(this); |
|
1806 } |
|
1807 }; |
|
1808 |
|
1809 // Assert that nsAutoTArray doesn't have any extra padding inside. |
|
1810 // |
|
1811 // It's important that the data stored in this auto array takes up a multiple of |
|
1812 // 8 bytes; e.g. nsAutoTArray<uint32_t, 1> wouldn't work. Since nsAutoTArray |
|
1813 // contains a pointer, its size must be a multiple of alignof(void*). (This is |
|
1814 // because any type may be placed into an array, and there's no padding between |
|
1815 // elements of an array.) The compiler pads the end of the structure to |
|
1816 // enforce this rule. |
|
1817 // |
|
1818 // If we used nsAutoTArray<uint32_t, 1> below, this assertion would fail on a |
|
1819 // 64-bit system, where the compiler inserts 4 bytes of padding at the end of |
|
1820 // the auto array to make its size a multiple of alignof(void*) == 8 bytes. |
|
1821 |
|
1822 static_assert(sizeof(nsAutoTArray<uint32_t, 2>) == |
|
1823 sizeof(void*) + sizeof(nsTArrayHeader) + sizeof(uint32_t) * 2, |
|
1824 "nsAutoTArray shouldn't contain any extra padding, " |
|
1825 "see the comment"); |
|
1826 |
|
1827 // Definitions of nsTArray_Impl methods |
|
1828 #include "nsTArray-inl.h" |
|
1829 |
|
1830 #endif // nsTArray_h__ |