]>
git.saurik.com Git - apple/javascriptcore.git/blob - wtf/Vector.h
1 // -*- mode: c++; c-basic-offset: 4 -*-
3 * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
25 #include "Assertions.h"
26 #include "FastMalloc.h"
27 #include "Noncopyable.h"
28 #include "VectorTraits.h"
39 template <bool needsDestruction
, typename T
>
40 class VectorDestructor
;
43 struct VectorDestructor
<false, T
>
45 static void destruct(T
*, T
*) {}
49 struct VectorDestructor
<true, T
>
51 static void destruct(T
* begin
, T
* end
)
53 for (T
* cur
= begin
; cur
!= end
; ++cur
)
58 template <bool needsInitialization
, bool canInitializeWithMemset
, typename T
>
59 class VectorInitializer
;
61 template<bool ignore
, typename T
>
62 struct VectorInitializer
<false, ignore
, T
>
64 static void initialize(T
*, T
*) {}
68 struct VectorInitializer
<true, false, T
>
70 static void initialize(T
* begin
, T
* end
)
72 for (T
* cur
= begin
; cur
!= end
; ++cur
)
78 struct VectorInitializer
<true, true, T
>
80 static void initialize(T
* begin
, T
* end
)
82 memset(begin
, 0, reinterpret_cast<char*>(end
) - reinterpret_cast<char*>(begin
));
86 template <bool canMoveWithMemcpy
, typename T
>
90 struct VectorMover
<false, T
>
92 static void move(const T
* src
, const T
* srcEnd
, T
* dst
)
94 while (src
!= srcEnd
) {
101 static void moveOverlapping(const T
* src
, const T
* srcEnd
, T
* dst
)
104 move(src
, srcEnd
, dst
);
106 T
* dstEnd
= dst
+ (srcEnd
- src
);
107 while (src
!= srcEnd
) {
110 new (dstEnd
) T(*srcEnd
);
118 struct VectorMover
<true, T
>
120 static void move(const T
* src
, const T
* srcEnd
, T
* dst
)
122 memcpy(dst
, src
, reinterpret_cast<const char*>(srcEnd
) - reinterpret_cast<const char*>(src
));
124 static void moveOverlapping(const T
* src
, const T
* srcEnd
, T
* dst
)
126 memmove(dst
, src
, reinterpret_cast<const char*>(srcEnd
) - reinterpret_cast<const char*>(src
));
130 template <bool canCopyWithMemcpy
, typename T
>
134 struct VectorCopier
<false, T
>
136 static void uninitializedCopy(const T
* src
, const T
* srcEnd
, T
* dst
)
138 while (src
!= srcEnd
) {
147 struct VectorCopier
<true, T
>
149 static void uninitializedCopy(const T
* src
, const T
* srcEnd
, T
* dst
)
151 memcpy(dst
, src
, reinterpret_cast<const char*>(srcEnd
) - reinterpret_cast<const char*>(src
));
155 template <bool canFillWithMemset
, typename T
>
159 struct VectorFiller
<false, T
>
161 static void uninitializedFill(T
* dst
, T
* dstEnd
, const T
& val
)
163 while (dst
!= dstEnd
) {
171 struct VectorFiller
<true, T
>
173 static void uninitializedFill(T
* dst
, T
* dstEnd
, const T
& val
)
175 ASSERT(sizeof(T
) == sizeof(char));
176 memset(dst
, val
, dstEnd
- dst
);
180 template<bool canCompareWithMemcmp
, typename T
>
181 class VectorComparer
;
184 struct VectorComparer
<false, T
>
186 static bool compare(const T
* a
, const T
* b
, size_t size
)
188 for (size_t i
= 0; i
< size
; ++i
)
196 struct VectorComparer
<true, T
>
198 static bool compare(const T
* a
, const T
* b
, size_t size
)
200 return memcmp(a
, b
, sizeof(T
) * size
) == 0;
205 struct VectorTypeOperations
207 static void destruct(T
* begin
, T
* end
)
209 VectorDestructor
<VectorTraits
<T
>::needsDestruction
, T
>::destruct(begin
, end
);
212 static void initialize(T
* begin
, T
* end
)
214 VectorInitializer
<VectorTraits
<T
>::needsInitialization
, VectorTraits
<T
>::canInitializeWithMemset
, T
>::initialize(begin
, end
);
217 static void move(const T
* src
, const T
* srcEnd
, T
* dst
)
219 VectorMover
<VectorTraits
<T
>::canMoveWithMemcpy
, T
>::move(src
, srcEnd
, dst
);
222 static void moveOverlapping(const T
* src
, const T
* srcEnd
, T
* dst
)
224 VectorMover
<VectorTraits
<T
>::canMoveWithMemcpy
, T
>::moveOverlapping(src
, srcEnd
, dst
);
227 static void uninitializedCopy(const T
* src
, const T
* srcEnd
, T
* dst
)
229 VectorCopier
<VectorTraits
<T
>::canCopyWithMemcpy
, T
>::uninitializedCopy(src
, srcEnd
, dst
);
232 static void uninitializedFill(T
* dst
, T
* dstEnd
, const T
& val
)
234 VectorFiller
<VectorTraits
<T
>::canFillWithMemset
, T
>::uninitializedFill(dst
, dstEnd
, val
);
237 static bool compare(const T
* a
, const T
* b
, size_t size
)
239 return VectorComparer
<VectorTraits
<T
>::canCompareWithMemcmp
, T
>::compare(a
, b
, size
);
244 class VectorBufferBase
: Noncopyable
{
246 void allocateBuffer(size_t newCapacity
)
248 ASSERT(newCapacity
>= m_capacity
);
249 m_capacity
= newCapacity
;
250 if (newCapacity
> std::numeric_limits
<size_t>::max() / sizeof(T
))
252 m_buffer
= static_cast<T
*>(fastMalloc(newCapacity
* sizeof(T
)));
255 void deallocateBuffer(T
* bufferToDeallocate
)
257 fastFree(bufferToDeallocate
);
260 T
* buffer() { return m_buffer
; }
261 const T
* buffer() const { return m_buffer
; }
262 size_t capacity() const { return m_capacity
; }
266 T
* buffer
= m_buffer
;
279 VectorBufferBase(T
* buffer
, size_t capacity
)
281 , m_capacity(capacity
)
287 // FIXME: It would be nice to find a way to ASSERT that m_buffer hasn't leaked here.
294 template<typename T
, size_t inlineCapacity
>
298 class VectorBuffer
<T
, 0> : private VectorBufferBase
<T
> {
300 typedef VectorBufferBase
<T
> Base
;
306 VectorBuffer(size_t capacity
)
308 allocateBuffer(capacity
);
313 deallocateBuffer(buffer());
316 void swap(VectorBuffer
<T
, 0>& other
)
318 std::swap(m_buffer
, other
.m_buffer
);
319 std::swap(m_capacity
, other
.m_capacity
);
322 using Base::allocateBuffer
;
323 using Base::deallocateBuffer
;
326 using Base::capacity
;
328 using Base::releaseBuffer
;
330 using Base::m_buffer
;
331 using Base::m_capacity
;
334 template<typename T
, size_t inlineCapacity
>
335 class VectorBuffer
: private VectorBufferBase
<T
> {
337 typedef VectorBufferBase
<T
> Base
;
340 : Base(inlineBuffer(), inlineCapacity
)
344 VectorBuffer(size_t capacity
)
345 : Base(inlineBuffer(), inlineCapacity
)
347 if (capacity
> inlineCapacity
)
348 allocateBuffer(capacity
);
353 deallocateBuffer(buffer());
356 using Base::allocateBuffer
;
358 void deallocateBuffer(T
* bufferToDeallocate
)
360 if (bufferToDeallocate
== inlineBuffer())
362 Base::deallocateBuffer(bufferToDeallocate
);
366 using Base::capacity
;
370 if (buffer() == inlineBuffer())
372 return Base::releaseBuffer();
376 using Base::m_buffer
;
377 using Base::m_capacity
;
379 static const size_t m_inlineBufferSize
= inlineCapacity
* sizeof(T
);
381 T
*inlineBuffer() { return reinterpret_cast<T
*>((void*)((&m_inlineBuffer
))); }
383 __attribute__ ((aligned (4))) char m_inlineBuffer
[m_inlineBufferSize
];
385 T
* inlineBuffer() { return reinterpret_cast<T
*>(&m_inlineBuffer
); }
387 // FIXME: Nothing guarantees this buffer is appropriately aligned to hold objects of type T.
388 char m_inlineBuffer
[m_inlineBufferSize
];
392 template<typename T
, size_t inlineCapacity
= 0>
395 typedef VectorBuffer
<T
, inlineCapacity
> Buffer
;
396 typedef VectorTypeOperations
<T
> TypeOperations
;
402 typedef const T
* const_iterator
;
409 explicit Vector(size_t size
)
413 TypeOperations::initialize(begin(), end());
421 Vector(const Vector
&);
422 template<size_t otherCapacity
>
423 Vector(const Vector
<T
, otherCapacity
>&);
425 Vector
& operator=(const Vector
&);
426 template<size_t otherCapacity
>
427 Vector
& operator=(const Vector
<T
, otherCapacity
>&);
429 size_t size() const { return m_size
; }
430 size_t capacity() const { return m_buffer
.capacity(); }
431 bool isEmpty() const { return !size(); }
436 return m_buffer
.buffer()[i
];
438 const T
& at(size_t i
) const
441 return m_buffer
.buffer()[i
];
444 T
& operator[](size_t i
) { return at(i
); }
445 const T
& operator[](size_t i
) const { return at(i
); }
447 T
* data() { return m_buffer
.buffer(); }
448 const T
* data() const { return m_buffer
.buffer(); }
450 iterator
begin() { return data(); }
451 iterator
end() { return begin() + m_size
; }
452 const_iterator
begin() const { return data(); }
453 const_iterator
end() const { return begin() + m_size
; }
455 T
& first() { return at(0); }
456 const T
& first() const { return at(0); }
457 T
& last() { return at(size() - 1); }
458 const T
& last() const { return at(size() - 1); }
460 void shrink(size_t size
);
461 void grow(size_t size
);
462 void resize(size_t size
);
463 void reserveCapacity(size_t newCapacity
);
465 void clear() { if (m_size
) shrink(0); }
467 template<typename U
> void append(const U
*, size_t);
468 template<typename U
> void append(const U
&);
469 template<typename U
> void uncheckedAppend(const U
& val
);
470 template<typename U
, size_t c
> void append(const Vector
<U
, c
>&);
472 template<typename U
> void insert(size_t position
, const U
*, size_t);
473 template<typename U
> void insert(size_t position
, const U
&);
474 template<typename U
, size_t c
> void insert(size_t position
, const Vector
<U
, c
>&);
476 template<typename U
> void prepend(const U
*, size_t);
477 template<typename U
> void prepend(const U
&);
478 template<typename U
, size_t c
> void prepend(const Vector
<U
, c
>&);
480 void remove(size_t position
);
488 Vector(size_t size
, const T
& val
)
492 TypeOperations::uninitializedFill(begin(), end(), val
);
495 void fill(const T
&, size_t);
496 void fill(const T
& val
) { fill(val
, size()); }
498 template<typename Iterator
> void appendRange(Iterator start
, Iterator end
);
502 void swap(Vector
<T
, inlineCapacity
>& other
)
504 std::swap(m_size
, other
.m_size
);
505 m_buffer
.swap(other
.m_buffer
);
509 void expandCapacity(size_t newMinCapacity
);
510 const T
* expandCapacity(size_t newMinCapacity
, const T
*);
511 template<typename U
> U
* expandCapacity(size_t newMinCapacity
, U
*);
517 template<typename T
, size_t inlineCapacity
>
518 Vector
<T
, inlineCapacity
>::Vector(const Vector
& other
)
519 : m_size(other
.size())
520 , m_buffer(other
.capacity())
522 TypeOperations::uninitializedCopy(other
.begin(), other
.end(), begin());
525 template<typename T
, size_t inlineCapacity
>
526 template<size_t otherCapacity
>
527 Vector
<T
, inlineCapacity
>::Vector(const Vector
<T
, otherCapacity
>& other
)
528 : m_size(other
.size())
529 , m_buffer(other
.capacity())
531 TypeOperations::uninitializedCopy(other
.begin(), other
.end(), begin());
534 template<typename T
, size_t inlineCapacity
>
535 Vector
<T
, inlineCapacity
>& Vector
<T
, inlineCapacity
>::operator=(const Vector
<T
, inlineCapacity
>& other
)
540 if (size() > other
.size())
541 shrink(other
.size());
542 else if (other
.size() > capacity()) {
544 reserveCapacity(other
.size());
547 std::copy(other
.begin(), other
.begin() + size(), begin());
548 TypeOperations::uninitializedCopy(other
.begin() + size(), other
.end(), end());
549 m_size
= other
.size();
554 template<typename T
, size_t inlineCapacity
>
555 template<size_t otherCapacity
>
556 Vector
<T
, inlineCapacity
>& Vector
<T
, inlineCapacity
>::operator=(const Vector
<T
, otherCapacity
>& other
)
561 if (size() > other
.size())
562 shrink(other
.size());
563 else if (other
.size() > capacity()) {
565 reserveCapacity(other
.size());
568 std::copy(other
.begin(), other
.begin() + size(), begin());
569 TypeOperations::uninitializedCopy(other
.begin() + size(), other
.end(), end());
570 m_size
= other
.size();
575 template<typename T
, size_t inlineCapacity
>
576 void Vector
<T
, inlineCapacity
>::fill(const T
& val
, size_t newSize
)
578 if (size() > newSize
)
580 else if (newSize
> capacity()) {
582 reserveCapacity(newSize
);
585 std::fill(begin(), end(), val
);
586 TypeOperations::uninitializedFill(end(), begin() + newSize
, val
);
590 template<typename T
, size_t inlineCapacity
>
591 template<typename Iterator
>
592 void Vector
<T
, inlineCapacity
>::appendRange(Iterator start
, Iterator end
)
594 for (Iterator it
= start
; it
!= end
; ++it
)
598 template<typename T
, size_t inlineCapacity
>
599 void Vector
<T
, inlineCapacity
>::expandCapacity(size_t newMinCapacity
)
601 reserveCapacity(max(newMinCapacity
, max(static_cast<size_t>(16), capacity() + capacity() / 4 + 1)));
604 template<typename T
, size_t inlineCapacity
>
605 const T
* Vector
<T
, inlineCapacity
>::expandCapacity(size_t newMinCapacity
, const T
* ptr
)
607 if (ptr
< begin() || ptr
>= end()) {
608 expandCapacity(newMinCapacity
);
611 size_t index
= ptr
- begin();
612 expandCapacity(newMinCapacity
);
613 return begin() + index
;
616 template<typename T
, size_t inlineCapacity
> template<typename U
>
617 inline U
* Vector
<T
, inlineCapacity
>::expandCapacity(size_t newMinCapacity
, U
* ptr
)
619 expandCapacity(newMinCapacity
);
623 template<typename T
, size_t inlineCapacity
>
624 void Vector
<T
, inlineCapacity
>::resize(size_t size
)
627 TypeOperations::destruct(begin() + size
, end());
629 if (size
> capacity())
630 expandCapacity(size
);
631 TypeOperations::initialize(end(), begin() + size
);
637 template<typename T
, size_t inlineCapacity
>
638 void Vector
<T
, inlineCapacity
>::shrink(size_t size
)
640 ASSERT(size
<= m_size
);
641 TypeOperations::destruct(begin() + size
, end());
645 template<typename T
, size_t inlineCapacity
>
646 void Vector
<T
, inlineCapacity
>::grow(size_t size
)
648 ASSERT(size
>= m_size
);
649 if (size
> capacity())
650 expandCapacity(size
);
651 TypeOperations::initialize(end(), begin() + size
);
655 template<typename T
, size_t inlineCapacity
>
656 void Vector
<T
, inlineCapacity
>::reserveCapacity(size_t newCapacity
)
658 if (newCapacity
<= capacity())
660 T
* oldBuffer
= begin();
662 m_buffer
.allocateBuffer(newCapacity
);
663 TypeOperations::move(oldBuffer
, oldEnd
, begin());
664 m_buffer
.deallocateBuffer(oldBuffer
);
667 // Templatizing these is better than just letting the conversion happen implicitly,
668 // because for instance it allows a PassRefPtr to be appended to a RefPtr vector
669 // without refcount thrash.
671 template<typename T
, size_t inlineCapacity
> template<typename U
>
672 void Vector
<T
, inlineCapacity
>::append(const U
* data
, size_t dataSize
)
674 size_t newSize
= m_size
+ dataSize
;
675 if (newSize
> capacity())
676 data
= expandCapacity(newSize
, data
);
678 for (size_t i
= 0; i
< dataSize
; ++i
)
679 new (&dest
[i
]) T(data
[i
]);
683 template<typename T
, size_t inlineCapacity
> template<typename U
>
684 inline void Vector
<T
, inlineCapacity
>::append(const U
& val
)
687 if (size() == capacity())
688 ptr
= expandCapacity(size() + 1, ptr
);
691 // FIXME: MSVC7 generates compilation errors when trying to assign
692 // a pointer to a Vector of its base class (i.e. can't downcast). So far
693 // I've been unable to determine any logical reason for this, so I can
694 // only assume it is a bug with the compiler. Casting is a bad solution,
695 // however, because it subverts implicit conversions, so a better
697 new (end()) T(static_cast<T
>(*ptr
));
704 // This version of append saves a branch in the case where you know that the
705 // vector's capacity is large enough for the append to succeed.
707 template<typename T
, size_t inlineCapacity
> template<typename U
>
708 inline void Vector
<T
, inlineCapacity
>::uncheckedAppend(const U
& val
)
710 ASSERT(size() < capacity());
716 template<typename T
, size_t inlineCapacity
> template<typename U
, size_t c
>
717 inline void Vector
<T
, inlineCapacity
>::append(const Vector
<U
, c
>& val
)
719 append(val
.begin(), val
.size());
722 template<typename T
, size_t inlineCapacity
> template<typename U
>
723 void Vector
<T
, inlineCapacity
>::insert(size_t position
, const U
* data
, size_t dataSize
)
725 ASSERT(position
<= size());
726 size_t newSize
= m_size
+ dataSize
;
727 if (newSize
> capacity())
728 data
= expandCapacity(newSize
, data
);
729 T
* spot
= begin() + position
;
730 TypeOperations::moveOverlapping(spot
, end(), spot
+ dataSize
);
731 for (size_t i
= 0; i
< dataSize
; ++i
)
732 new (&spot
[i
]) T(data
[i
]);
736 template<typename T
, size_t inlineCapacity
> template<typename U
>
737 inline void Vector
<T
, inlineCapacity
>::insert(size_t position
, const U
& val
)
739 ASSERT(position
<= size());
740 const U
* data
= &val
;
741 if (size() == capacity())
742 data
= expandCapacity(size() + 1, data
);
743 T
* spot
= begin() + position
;
744 TypeOperations::moveOverlapping(spot
, end(), spot
+ 1);
749 template<typename T
, size_t inlineCapacity
> template<typename U
, size_t c
>
750 inline void Vector
<T
, inlineCapacity
>::insert(size_t position
, const Vector
<U
, c
>& val
)
752 insert(position
, val
.begin(), val
.size());
755 template<typename T
, size_t inlineCapacity
> template<typename U
>
756 void Vector
<T
, inlineCapacity
>::prepend(const U
* data
, size_t dataSize
)
758 insert(0, data
, dataSize
);
761 template<typename T
, size_t inlineCapacity
> template<typename U
>
762 inline void Vector
<T
, inlineCapacity
>::prepend(const U
& val
)
767 template<typename T
, size_t inlineCapacity
> template<typename U
, size_t c
>
768 inline void Vector
<T
, inlineCapacity
>::prepend(const Vector
<U
, c
>& val
)
770 insert(0, val
.begin(), val
.size());
773 template<typename T
, size_t inlineCapacity
>
774 inline void Vector
<T
, inlineCapacity
>::remove(size_t position
)
776 ASSERT(position
< size());
777 T
* spot
= begin() + position
;
779 TypeOperations::moveOverlapping(spot
+ 1, end(), spot
);
783 template<typename T
, size_t inlineCapacity
>
784 inline T
* Vector
<T
, inlineCapacity
>::releaseBuffer()
786 T
* buffer
= m_buffer
.releaseBuffer();
787 if (inlineCapacity
&& !buffer
&& m_size
) {
788 // If the vector had some data, but no buffer to release,
789 // that means it was using the inline buffer. In that case,
790 // we create a brand new buffer so the caller always gets one.
791 size_t bytes
= m_size
* sizeof(T
);
792 buffer
= static_cast<T
*>(fastMalloc(bytes
));
793 memcpy(buffer
, data(), bytes
);
800 template<typename T
, size_t inlineCapacity
>
801 void deleteAllValues(const Vector
<T
, inlineCapacity
>& collection
)
803 typedef typename Vector
<T
, inlineCapacity
>::const_iterator iterator
;
804 iterator end
= collection
.end();
805 for (iterator it
= collection
.begin(); it
!= end
; ++it
)
809 template<typename T
, size_t inlineCapacity
>
810 inline void swap(Vector
<T
, inlineCapacity
>& a
, Vector
<T
, inlineCapacity
>& b
)
815 template<typename T
, size_t inlineCapacity
>
816 bool operator==(const Vector
<T
, inlineCapacity
>& a
, const Vector
<T
, inlineCapacity
>& b
)
818 if (a
.size() != b
.size())
821 return VectorTypeOperations
<T
>::compare(a
.data(), b
.data(), a
.size());
824 template<typename T
, size_t inlineCapacity
>
825 inline bool operator!=(const Vector
<T
, inlineCapacity
>& a
, const Vector
<T
, inlineCapacity
>& b
)
835 #endif // WTF_Vector_h