Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / jsvector.h
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * vim: set ts=8 sw=4 et tw=99 ft=cpp:
3  *
4  * ***** BEGIN LICENSE BLOCK *****
5  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
18  * June 12, 2009.
19  *
20  * The Initial Developer of the Original Code is
21  *   the Mozilla Corporation.
22  *
23  * Contributor(s):
24  *   Luke Wagner <lw@mozilla.com>
25  *   Nicholas Nethercote <nnethercote@mozilla.com>
26  *
27  * Alternatively, the contents of this file may be used under the terms of
28  * either of the GNU General Public License Version 2 or later (the "GPL"),
29  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30  * in which case the provisions of the GPL or the LGPL are applicable instead
31  * of those above. If you wish to allow use of your version of this file only
32  * under the terms of either the GPL or the LGPL, and not to allow others to
33  * use your version of this file under the terms of the MPL, indicate your
34  * decision by deleting the provisions above and replace them with the notice
35  * and other provisions required by the GPL or the LGPL. If you do not delete
36  * the provisions above, a recipient may use your version of this file under
37  * the terms of any one of the MPL, the GPL or the LGPL.
38  *
39  * ***** END LICENSE BLOCK ***** */
40
41 #ifndef jsvector_h_
42 #define jsvector_h_
43
44 #include "jstl.h"
45 #include "jsprvtd.h"
46
47 /* Silence dire "bugs in previous versions of MSVC have been fixed" warnings */
48 #ifdef _MSC_VER
49 #pragma warning(push)
50 #pragma warning(disable:4345)
51 #endif
52
53 /* Gross special case for Gecko, which defines malloc/calloc/free. */
54 #ifdef mozilla_mozalloc_macro_wrappers_h
55 #  define JSVECTOR_UNDEFD_MOZALLOC_WRAPPERS
56 #  include "mozilla/mozalloc_undef_macro_wrappers.h"
57 #endif
58
59 namespace js {
60
61 /*
62  * This template class provides a default implementation for vector operations
63  * when the element type is not known to be a POD, as judged by IsPodType.
64  */
65 template <class T, size_t N, class AP, bool IsPod>
66 struct VectorImpl
67 {
68     /* Destroys constructed objects in the range [begin, end). */
69     static inline void destroy(T *begin, T *end) {
70         for (T *p = begin; p != end; ++p)
71             p->~T();
72     }
73
74     /* Constructs objects in the uninitialized range [begin, end). */
75     static inline void initialize(T *begin, T *end) {
76         for (T *p = begin; p != end; ++p)
77             new(p) T();
78     }
79
80     /*
81      * Copy-constructs objects in the uninitialized range
82      * [dst, dst+(srcend-srcbeg)) from the range [srcbeg, srcend).
83      */
84     template <class U>
85     static inline void copyConstruct(T *dst, const U *srcbeg, const U *srcend) {
86         for (const U *p = srcbeg; p != srcend; ++p, ++dst)
87             new(dst) T(*p);
88     }
89
90     /*
91      * Copy-constructs objects in the uninitialized range [dst, dst+n) from the
92      * same object u.
93      */
94     template <class U>
95     static inline void copyConstructN(T *dst, size_t n, const U &u) {
96         for (T *end = dst + n; dst != end; ++dst)
97             new(dst) T(u);
98     }
99
100     /*
101      * Grows the given buffer to have capacity newcap, preserving the objects
102      * constructed in the range [begin, end) and updating v. Assumes that (1)
103      * newcap has not overflowed, and (2) multiplying newcap by sizeof(T) will
104      * not overflow.
105      */
106     static inline bool growTo(Vector<T,N,AP> &v, size_t newcap) {
107         JS_ASSERT(!v.usingInlineStorage());
108         T *newbuf = reinterpret_cast<T *>(v.malloc(newcap * sizeof(T)));
109         if (!newbuf)
110             return false;
111         for (T *dst = newbuf, *src = v.beginNoCheck(); src != v.endNoCheck(); ++dst, ++src)
112             new(dst) T(*src);
113         VectorImpl::destroy(v.beginNoCheck(), v.endNoCheck());
114         v.free(v.mBegin);
115         v.mBegin = newbuf;
116         /* v.mLength is unchanged. */
117         v.mCapacity = newcap;
118         return true;
119     }
120 };
121
122 /*
123  * This partial template specialization provides a default implementation for
124  * vector operations when the element type is known to be a POD, as judged by
125  * IsPodType.
126  */
127 template <class T, size_t N, class AP>
128 struct VectorImpl<T, N, AP, true>
129 {
130     static inline void destroy(T *, T *) {}
131
132     static inline void initialize(T *begin, T *end) {
133         /*
134          * You would think that memset would be a big win (or even break even)
135          * when we know T is a POD. But currently it's not. This is probably
136          * because |append| tends to be given small ranges and memset requires
137          * a function call that doesn't get inlined.
138          *
139          * memset(begin, 0, sizeof(T) * (end-begin));
140          */
141         for (T *p = begin; p != end; ++p)
142             new(p) T();
143     }
144
145     template <class U>
146     static inline void copyConstruct(T *dst, const U *srcbeg, const U *srcend) {
147         /*
148          * See above memset comment. Also, notice that copyConstruct is
149          * currently templated (T != U), so memcpy won't work without
150          * requiring T == U.
151          *
152          * memcpy(dst, srcbeg, sizeof(T) * (srcend - srcbeg));
153          */
154         for (const U *p = srcbeg; p != srcend; ++p, ++dst)
155             *dst = *p;
156     }
157
158     static inline void copyConstructN(T *dst, size_t n, const T &t) {
159         for (T *p = dst, *end = dst + n; p != end; ++p)
160             *p = t;
161     }
162
163     static inline bool growTo(Vector<T,N,AP> &v, size_t newcap) {
164         JS_ASSERT(!v.usingInlineStorage());
165         size_t bytes = sizeof(T) * newcap;
166         T *newbuf = reinterpret_cast<T *>(v.realloc(v.mBegin, bytes));
167         if (!newbuf)
168             return false;
169         v.mBegin = newbuf;
170         /* v.mLength is unchanged. */
171         v.mCapacity = newcap;
172         return true;
173     }
174 };
175
176 /*
177  * JS-friendly, STL-like container providing a short-lived, dynamic buffer.
178  * Vector calls the constructors/destructors of all elements stored in
179  * its internal buffer, so non-PODs may be safely used. Additionally,
180  * Vector will store the first N elements in-place before resorting to
181  * dynamic allocation.
182  *
183  * T requirements:
184  *  - default and copy constructible, assignable, destructible
185  *  - operations do not throw
186  * N requirements:
187  *  - any value, however, N is clamped to min/max values
188  * AllocPolicy:
189  *  - see "Allocation policies" in jstl.h (default ContextAllocPolicy)
190  *
191  * N.B: Vector is not reentrant: T member functions called during Vector member
192  *      functions must not call back into the same object.
193  */
194 template <class T, size_t N, class AllocPolicy>
195 class Vector : AllocPolicy
196 {
197     /* utilities */
198
199     static const bool sElemIsPod = tl::IsPodType<T>::result;
200     typedef VectorImpl<T, N, AllocPolicy, sElemIsPod> Impl;
201     friend struct VectorImpl<T, N, AllocPolicy, sElemIsPod>;
202
203     bool calculateNewCapacity(size_t curLength, size_t lengthInc, size_t &newCap);
204     bool growStorageBy(size_t lengthInc);
205     bool growHeapStorageBy(size_t lengthInc);
206     bool convertToHeapStorage(size_t lengthInc);
207
208     template <bool InitNewElems> inline bool growByImpl(size_t inc);
209
210     /* magic constants */
211
212     static const int sMaxInlineBytes = 1024;
213
214     /* compute constants */
215
216     static const size_t sInlineCapacity =
217         tl::Min<N, sMaxInlineBytes / sizeof(T)>::result;
218
219     /* Calculate inline buffer size; avoid 0-sized array. */
220     static const size_t sInlineBytes =
221         tl::Max<1, sInlineCapacity * sizeof(T)>::result;
222
223     /* member data */
224
225     /*
226      * Pointer to the buffer, be it inline or heap-allocated. Only [mBegin,
227      * mBegin + mLength) hold valid constructed T objects. The range [mBegin +
228      * mLength, mBegin + mCapacity) holds uninitialized memory.
229      */
230     T *mBegin;
231     size_t mLength;     /* Number of elements in the Vector. */
232     size_t mCapacity;   /* Max number of elements storable in the Vector without resizing. */
233
234     AlignedStorage<sInlineBytes> storage;
235
236 #ifdef DEBUG
237     friend class ReentrancyGuard;
238     bool entered;
239 #endif
240
241     Vector(const Vector &);
242     Vector &operator=(const Vector &);
243
244     /* private accessors */
245
246     bool usingInlineStorage() const {
247         return mBegin == (T *)storage.addr();
248     }
249
250     T *beginNoCheck() const {
251         return mBegin;
252     }
253
254     T *endNoCheck() {
255         return mBegin + mLength;
256     }
257
258     const T *endNoCheck() const {
259         return mBegin + mLength;
260     }
261
262   public:
263     typedef T ElementType;
264
265     Vector(AllocPolicy = AllocPolicy());
266     ~Vector();
267
268     /* accessors */
269
270     const AllocPolicy &allocPolicy() const {
271         return *this;
272     }
273
274     enum { InlineLength = N };
275
276     size_t length() const {
277         return mLength;
278     }
279
280     bool empty() const {
281         return mLength == 0;
282     }
283
284     size_t capacity() const {
285         return mCapacity;
286     }
287
288     T *begin() const {
289         JS_ASSERT(!entered);
290         return mBegin;
291     }
292
293     T *end() {
294         JS_ASSERT(!entered);
295         return mBegin + mLength;
296     }
297
298     const T *end() const {
299         JS_ASSERT(!entered);
300         return mBegin + mLength;
301     }
302
303     T &operator[](size_t i) {
304         JS_ASSERT(!entered && i < mLength);
305         return begin()[i];
306     }
307
308     const T &operator[](size_t i) const {
309         JS_ASSERT(!entered && i < mLength);
310         return begin()[i];
311     }
312
313     T &back() {
314         JS_ASSERT(!entered && !empty());
315         return *(end() - 1);
316     }
317
318     const T &back() const {
319         JS_ASSERT(!entered && !empty());
320         return *(end() - 1);
321     }
322
323     /* mutators */
324
325     /* If reserve(length() + N) succeeds, the N next appends are guaranteed to succeed. */
326     bool reserve(size_t capacity);
327
328     /* Destroy elements in the range [begin() + incr, end()). */
329     void shrinkBy(size_t incr);
330
331     /* Grow the vector by incr elements. */
332     bool growBy(size_t incr);
333
334     /* Call shrinkBy or growBy based on whether newSize > length(). */
335     bool resize(size_t newLength);
336
337     /* Leave new elements as uninitialized memory. */
338     bool growByUninitialized(size_t incr);
339     bool resizeUninitialized(size_t newLength);
340
341     void clear();
342
343     bool append(const T &t);
344     bool appendN(const T &t, size_t n);
345     template <class U> bool append(const U *begin, const U *end);
346     template <class U> bool append(const U *begin, size_t length);
347     template <class U, size_t O, class BP> bool append(const Vector<U,O,BP> &other);
348
349     void popBack();
350
351     T popCopy();
352
353     /*
354      * Transfers ownership of the internal buffer used by Vector to the caller.
355      * After this call, the Vector is empty. Since the returned buffer may need
356      * to be allocated (if the elements are currently stored in-place), the
357      * call can fail, returning NULL.
358      *
359      * N.B. Although a T*, only the range [0, length()) is constructed.
360      */
361     T *extractRawBuffer();
362
363     /*
364      * Transfer ownership of an array of objects into the Vector.
365      * N.B. This call assumes that there are no uninitialized elements in the
366      *      passed array.
367      */
368     void replaceRawBuffer(T *p, size_t length);
369
370     /*
371      * Places |val| at position |p|, shifting existing elements
372      * from |p| onward one position higher.
373      */
374     bool insert(T *p, const T &val);
375
376     /*
377      * Removes the element |t|, which must fall in the bounds [begin, end),
378      * shifting existing elements from |t + 1| onward one position lower.
379      */
380     void erase(T *t);
381 };
382
383 /* This does the re-entrancy check plus several other sanity checks. */
384 #define REENTRANCY_GUARD_ET_AL \
385     ReentrancyGuard g(*this); \
386     JS_ASSERT_IF(usingInlineStorage(), mCapacity == sInlineCapacity); \
387     JS_ASSERT(mLength <= mCapacity)
388
389 /* Vector Implementation */
390
391 template <class T, size_t N, class AllocPolicy>
392 JS_ALWAYS_INLINE
393 Vector<T,N,AllocPolicy>::Vector(AllocPolicy ap)
394   : AllocPolicy(ap), mBegin((T *)storage.addr()), mLength(0),
395     mCapacity(sInlineCapacity)
396 #ifdef DEBUG
397   , entered(false)
398 #endif
399 {}
400
401 template <class T, size_t N, class AP>
402 JS_ALWAYS_INLINE
403 Vector<T,N,AP>::~Vector()
404 {
405     REENTRANCY_GUARD_ET_AL;
406     Impl::destroy(beginNoCheck(), endNoCheck());
407     if (!usingInlineStorage())
408         this->free(beginNoCheck());
409 }
410
411 /*
412  * Calculate a new capacity that is at least lengthInc greater than
413  * curLength and check for overflow.
414  */
415 template <class T, size_t N, class AP>
416 STATIC_POSTCONDITION(!return || newCap >= curLength + lengthInc)
417 inline bool
418 Vector<T,N,AP>::calculateNewCapacity(size_t curLength, size_t lengthInc,
419                                      size_t &newCap)
420 {
421     size_t newMinCap = curLength + lengthInc;
422
423     /*
424      * Check for overflow in the above addition, below CEILING_LOG2, and later
425      * multiplication by sizeof(T).
426      */
427     if (newMinCap < curLength ||
428         newMinCap & tl::MulOverflowMask<2 * sizeof(T)>::result) {
429         this->reportAllocOverflow();
430         return false;
431     }
432
433     /* Round up to next power of 2. */
434     newCap = RoundUpPow2(newMinCap);
435
436     /*
437      * Do not allow a buffer large enough that the expression ((char *)end() -
438      * (char *)begin()) overflows ptrdiff_t. See Bug 510319.
439      */
440     if (newCap & tl::UnsafeRangeSizeMask<T>::result) {
441         this->reportAllocOverflow();
442         return false;
443     }
444     return true;
445 }
446
447 /*
448  * This function will grow the current heap capacity to have capacity
449  * (mLength + lengthInc) and fail on OOM or integer overflow.
450  */
451 template <class T, size_t N, class AP>
452 JS_ALWAYS_INLINE bool
453 Vector<T,N,AP>::growHeapStorageBy(size_t lengthInc)
454 {
455     JS_ASSERT(!usingInlineStorage());
456     size_t newCap;
457     return calculateNewCapacity(mLength, lengthInc, newCap) &&
458            Impl::growTo(*this, newCap);
459 }
460
461 /*
462  * This function will create a new heap buffer with capacity (mLength +
463  * lengthInc()), move all elements in the inline buffer to this new buffer,
464  * and fail on OOM or integer overflow.
465  */
466 template <class T, size_t N, class AP>
467 inline bool
468 Vector<T,N,AP>::convertToHeapStorage(size_t lengthInc)
469 {
470     JS_ASSERT(usingInlineStorage());
471     size_t newCap;
472     if (!calculateNewCapacity(mLength, lengthInc, newCap))
473         return false;
474
475     /* Allocate buffer. */
476     T *newBuf = reinterpret_cast<T *>(this->malloc(newCap * sizeof(T)));
477     if (!newBuf)
478         return false;
479
480     /* Copy inline elements into heap buffer. */
481     Impl::copyConstruct(newBuf, beginNoCheck(), endNoCheck());
482     Impl::destroy(beginNoCheck(), endNoCheck());
483
484     /* Switch in heap buffer. */
485     mBegin = newBuf;
486     /* mLength is unchanged. */
487     mCapacity = newCap;
488     return true;
489 }
490
491 template <class T, size_t N, class AP>
492 JS_NEVER_INLINE bool
493 Vector<T,N,AP>::growStorageBy(size_t incr)
494 {
495     JS_ASSERT(mLength + incr > mCapacity);
496     return usingInlineStorage()
497          ? convertToHeapStorage(incr)
498          : growHeapStorageBy(incr);
499 }
500
501 template <class T, size_t N, class AP>
502 inline bool
503 Vector<T,N,AP>::reserve(size_t request)
504 {
505     REENTRANCY_GUARD_ET_AL;
506     if (request > mCapacity)
507         return growStorageBy(request - mLength);
508     return true;
509 }
510
511 template <class T, size_t N, class AP>
512 inline void
513 Vector<T,N,AP>::shrinkBy(size_t incr)
514 {
515     REENTRANCY_GUARD_ET_AL;
516     JS_ASSERT(incr <= mLength);
517     Impl::destroy(endNoCheck() - incr, endNoCheck());
518     mLength -= incr;
519 }
520
521 template <class T, size_t N, class AP>
522 template <bool InitNewElems>
523 JS_ALWAYS_INLINE bool
524 Vector<T,N,AP>::growByImpl(size_t incr)
525 {
526     REENTRANCY_GUARD_ET_AL;
527     if (incr > mCapacity - mLength && !growStorageBy(incr))
528         return false;
529
530     JS_ASSERT(mLength + incr <= mCapacity);
531     T *newend = endNoCheck() + incr;
532     if (InitNewElems)
533         Impl::initialize(endNoCheck(), newend);
534     mLength += incr;
535     return true;
536 }
537
538 template <class T, size_t N, class AP>
539 JS_ALWAYS_INLINE bool
540 Vector<T,N,AP>::growBy(size_t incr)
541 {
542     return growByImpl<true>(incr);
543 }
544
545 template <class T, size_t N, class AP>
546 JS_ALWAYS_INLINE bool
547 Vector<T,N,AP>::growByUninitialized(size_t incr)
548 {
549     return growByImpl<false>(incr);
550 }
551
552 template <class T, size_t N, class AP>
553 STATIC_POSTCONDITION(!return || ubound(this->begin()) >= newLength)
554 inline bool
555 Vector<T,N,AP>::resize(size_t newLength)
556 {
557     size_t curLength = mLength;
558     if (newLength > curLength)
559         return growBy(newLength - curLength);
560     shrinkBy(curLength - newLength);
561     return true;
562 }
563
564 template <class T, size_t N, class AP>
565 JS_ALWAYS_INLINE bool
566 Vector<T,N,AP>::resizeUninitialized(size_t newLength)
567 {
568     size_t curLength = mLength;
569     if (newLength > curLength)
570         return growByUninitialized(newLength - curLength);
571     shrinkBy(curLength - newLength);
572     return true;
573 }
574
575 template <class T, size_t N, class AP>
576 inline void
577 Vector<T,N,AP>::clear()
578 {
579     REENTRANCY_GUARD_ET_AL;
580     Impl::destroy(beginNoCheck(), endNoCheck());
581     mLength = 0;
582 }
583
584 template <class T, size_t N, class AP>
585 JS_ALWAYS_INLINE bool
586 Vector<T,N,AP>::append(const T &t)
587 {
588     REENTRANCY_GUARD_ET_AL;
589     if (mLength == mCapacity && !growStorageBy(1))
590         return false;
591
592     JS_ASSERT(mLength < mCapacity);
593     new(endNoCheck()) T(t);
594     ++mLength;
595     return true;
596 }
597
598 template <class T, size_t N, class AP>
599 JS_ALWAYS_INLINE bool
600 Vector<T,N,AP>::appendN(const T &t, size_t needed)
601 {
602     REENTRANCY_GUARD_ET_AL;
603     if (mLength + needed > mCapacity && !growStorageBy(needed))
604         return false;
605
606     JS_ASSERT(mLength + needed <= mCapacity);
607     Impl::copyConstructN(endNoCheck(), needed, t);
608     mLength += needed;
609     return true;
610 }
611
612 template <class T, size_t N, class AP>
613 inline bool
614 Vector<T,N,AP>::insert(T *p, const T &val)
615 {
616     JS_ASSERT(begin() <= p && p <= end());
617     size_t pos = p - begin();
618     JS_ASSERT(pos <= mLength);
619     size_t oldLength = mLength;
620     if (pos == oldLength)
621         return append(val);
622     {
623         T oldBack = back();
624         if (!append(oldBack)) /* Dup the last element. */
625             return false;
626     }
627     for (size_t i = oldLength; i > pos; --i)
628         (*this)[i] = (*this)[i - 1];
629     (*this)[pos] = val;
630     return true;
631 }
632
633 template<typename T, size_t N, class AP>
634 inline void
635 Vector<T,N,AP>::erase(T *it)
636 {
637     JS_ASSERT(begin() <= it && it < end());
638     while (it + 1 != end()) {
639         *it = *(it + 1);
640         ++it;
641     }
642     popBack();
643 }
644
645 template <class T, size_t N, class AP>
646 template <class U>
647 JS_ALWAYS_INLINE bool
648 Vector<T,N,AP>::append(const U *insBegin, const U *insEnd)
649 {
650     REENTRANCY_GUARD_ET_AL;
651     size_t needed = PointerRangeSize(insBegin, insEnd);
652     if (mLength + needed > mCapacity && !growStorageBy(needed))
653         return false;
654
655     JS_ASSERT(mLength + needed <= mCapacity);
656     Impl::copyConstruct(endNoCheck(), insBegin, insEnd);
657     mLength += needed;
658     return true;
659 }
660
661 template <class T, size_t N, class AP>
662 template <class U, size_t O, class BP>
663 inline bool
664 Vector<T,N,AP>::append(const Vector<U,O,BP> &other)
665 {
666     return append(other.begin(), other.end());
667 }
668
669 template <class T, size_t N, class AP>
670 template <class U>
671 JS_ALWAYS_INLINE bool
672 Vector<T,N,AP>::append(const U *insBegin, size_t length)
673 {
674     return this->append(insBegin, insBegin + length);
675 }
676
677 template <class T, size_t N, class AP>
678 JS_ALWAYS_INLINE void
679 Vector<T,N,AP>::popBack()
680 {
681     REENTRANCY_GUARD_ET_AL;
682     JS_ASSERT(!empty());
683     --mLength;
684     endNoCheck()->~T();
685 }
686
687 template <class T, size_t N, class AP>
688 JS_ALWAYS_INLINE T
689 Vector<T,N,AP>::popCopy()
690 {
691     T ret = back();
692     popBack();
693     return ret;
694 }
695
696 template <class T, size_t N, class AP>
697 inline T *
698 Vector<T,N,AP>::extractRawBuffer()
699 {
700     T *ret;
701     if (usingInlineStorage()) {
702         ret = reinterpret_cast<T *>(this->malloc(mLength * sizeof(T)));
703         if (!ret)
704             return NULL;
705         Impl::copyConstruct(ret, beginNoCheck(), endNoCheck());
706         Impl::destroy(beginNoCheck(), endNoCheck());
707         /* mBegin, mCapacity are unchanged. */
708         mLength = 0;
709     } else {
710         ret = mBegin;
711         mBegin = (T *)storage.addr();
712         mLength = 0;
713         mCapacity = sInlineCapacity;
714     }
715     return ret;
716 }
717
718 template <class T, size_t N, class AP>
719 inline void
720 Vector<T,N,AP>::replaceRawBuffer(T *p, size_t length)
721 {
722     REENTRANCY_GUARD_ET_AL;
723
724     /* Destroy what we have. */
725     Impl::destroy(beginNoCheck(), endNoCheck());
726     if (!usingInlineStorage())
727         this->free(beginNoCheck());
728
729     /* Take in the new buffer. */
730     if (length <= sInlineCapacity) {
731         /*
732          * We convert to inline storage if possible, even though p might
733          * otherwise be acceptable.  Maybe this behaviour should be
734          * specifiable with an argument to this function.
735          */
736         mBegin = (T *)storage.addr();
737         mLength = length;
738         mCapacity = sInlineCapacity;
739         Impl::copyConstruct(mBegin, p, p + length);
740         Impl::destroy(p, p + length);
741         this->free(p);
742     } else {
743         mBegin = p;
744         mLength = length;
745         mCapacity = length;
746     }
747 }
748
749 }  /* namespace js */
750
751 #ifdef _MSC_VER
752 #pragma warning(pop)
753 #endif
754
755 #ifdef JSVECTOR_UNDEFD_MOZALLOC_WRAPPERS
756 #  include "mozilla/mozalloc_macro_wrappers.h"
757 #endif
758
759 #endif /* jsvector_h_ */