/[jscoverage]/trunk/js/jsvector.h
ViewVC logotype

Contents of /trunk/js/jsvector.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 507 - (show annotations)
Sun Jan 10 07:23:34 2010 UTC (9 years, 7 months ago) by siliconforks
File MIME type: text/plain
File size: 23117 byte(s)
Update SpiderMonkey from Firefox 3.6rc1.

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

  ViewVC Help
Powered by ViewVC 1.1.24