1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef V8_UTIL_H_
6 #define V8_UTIL_H_
7 
8 #include <assert.h>
9 
10 #include <map>
11 #include <vector>
12 
13 #include "v8-function-callback.h"  // NOLINT(build/include_directory)
14 #include "v8-persistent-handle.h"  // NOLINT(build/include_directory)
15 
16 /**
17  * Support for Persistent containers.
18  *
19  * C++11 embedders can use STL containers with Global values,
20  * but pre-C++11 does not support the required move semantic and hence
21  * may want these container classes.
22  */
23 namespace v8 {
24 
25 template <typename K, typename V, typename Traits>
26 class GlobalValueMap;
27 
28 typedef uintptr_t PersistentContainerValue;
29 static const uintptr_t kPersistentContainerNotFound = 0;
30 enum PersistentContainerCallbackType {
31   kNotWeak,
32   // These correspond to v8::WeakCallbackType
33   kWeakWithParameter,
34   kWeakWithInternalFields
35 };
36 
37 /**
38  * A default trait implementation for PersistentValueMap which uses std::map
39  * as a backing map.
40  *
41  * Users will have to implement their own weak callbacks & dispose traits.
42  */
43 template<typename K, typename V>
44 class StdMapTraits {
45  public:
46   // STL map & related:
47   typedef std::map<K, PersistentContainerValue> Impl;
48   typedef typename Impl::iterator Iterator;
49 
Empty(Impl* impl)50   static bool Empty(Impl* impl) { return impl->empty(); }
Size(Impl* impl)51   static size_t Size(Impl* impl) { return impl->size(); }
Swap(Impl& a, Impl& b)52   static void Swap(Impl& a, Impl& b) { std::swap(a, b); }
Begin(Impl* impl)53   static Iterator Begin(Impl* impl) { return impl->begin(); }
End(Impl* impl)54   static Iterator End(Impl* impl) { return impl->end(); }
Key(Iterator it)55   static K Key(Iterator it) { return it->first; }
Value(Iterator it)56   static PersistentContainerValue Value(Iterator it) { return it->second; }
Set(Impl* impl, K key, PersistentContainerValue value)57   static PersistentContainerValue Set(Impl* impl, K key,
58       PersistentContainerValue value) {
59     std::pair<Iterator, bool> res = impl->insert(std::make_pair(key, value));
60     PersistentContainerValue old_value = kPersistentContainerNotFound;
61     if (!res.second) {
62       old_value = res.first->second;
63       res.first->second = value;
64     }
65     return old_value;
66   }
Get(Impl* impl, K key)67   static PersistentContainerValue Get(Impl* impl, K key) {
68     Iterator it = impl->find(key);
69     if (it == impl->end()) return kPersistentContainerNotFound;
70     return it->second;
71   }
Remove(Impl* impl, K key)72   static PersistentContainerValue Remove(Impl* impl, K key) {
73     Iterator it = impl->find(key);
74     if (it == impl->end()) return kPersistentContainerNotFound;
75     PersistentContainerValue value = it->second;
76     impl->erase(it);
77     return value;
78   }
79 };
80 
81 
82 /**
83  * A default trait implementation for PersistentValueMap, which inherits
84  * a std:map backing map from StdMapTraits and holds non-weak persistent
85  * objects and has no special Dispose handling.
86  *
87  * You should not derive from this class, since MapType depends on the
88  * surrounding class, and hence a subclass cannot simply inherit the methods.
89  */
90 template<typename K, typename V>
91 class DefaultPersistentValueMapTraits : public StdMapTraits<K, V> {
92  public:
93   // Weak callback & friends:
94   static const PersistentContainerCallbackType kCallbackType = kNotWeak;
95   typedef PersistentValueMap<K, V, DefaultPersistentValueMapTraits<K, V> >
96       MapType;
97   typedef void WeakCallbackDataType;
98 
WeakCallbackParameter( MapType* map, const K& key, Local<V> value)99   static WeakCallbackDataType* WeakCallbackParameter(
100       MapType* map, const K& key, Local<V> value) {
101     return nullptr;
102   }
MapFromWeakCallbackInfo( const WeakCallbackInfo<WeakCallbackDataType>& data)103   static MapType* MapFromWeakCallbackInfo(
104       const WeakCallbackInfo<WeakCallbackDataType>& data) {
105     return nullptr;
106   }
KeyFromWeakCallbackInfo( const WeakCallbackInfo<WeakCallbackDataType>& data)107   static K KeyFromWeakCallbackInfo(
108       const WeakCallbackInfo<WeakCallbackDataType>& data) {
109     return K();
110   }
DisposeCallbackData(WeakCallbackDataType* data)111   static void DisposeCallbackData(WeakCallbackDataType* data) { }
Dispose(Isolate* isolate, Global<V> value, K key)112   static void Dispose(Isolate* isolate, Global<V> value, K key) {}
113 };
114 
115 
116 template <typename K, typename V>
117 class DefaultGlobalMapTraits : public StdMapTraits<K, V> {
118  private:
119   template <typename T>
120   struct RemovePointer;
121 
122  public:
123   // Weak callback & friends:
124   static const PersistentContainerCallbackType kCallbackType = kNotWeak;
125   typedef GlobalValueMap<K, V, DefaultGlobalMapTraits<K, V> > MapType;
126   typedef void WeakCallbackDataType;
127 
WeakCallbackParameter(MapType* map, const K& key, Local<V> value)128   static WeakCallbackDataType* WeakCallbackParameter(MapType* map, const K& key,
129                                                      Local<V> value) {
130     return nullptr;
131   }
MapFromWeakCallbackInfo( const WeakCallbackInfo<WeakCallbackDataType>& data)132   static MapType* MapFromWeakCallbackInfo(
133       const WeakCallbackInfo<WeakCallbackDataType>& data) {
134     return nullptr;
135   }
KeyFromWeakCallbackInfo( const WeakCallbackInfo<WeakCallbackDataType>& data)136   static K KeyFromWeakCallbackInfo(
137       const WeakCallbackInfo<WeakCallbackDataType>& data) {
138     return K();
139   }
DisposeCallbackData(WeakCallbackDataType* data)140   static void DisposeCallbackData(WeakCallbackDataType* data) {}
OnWeakCallback( const WeakCallbackInfo<WeakCallbackDataType>& data)141   static void OnWeakCallback(
142       const WeakCallbackInfo<WeakCallbackDataType>& data) {}
Dispose(Isolate* isolate, Global<V> value, K key)143   static void Dispose(Isolate* isolate, Global<V> value, K key) {}
144   // This is a second pass callback, so SetSecondPassCallback cannot be called.
DisposeWeak(const WeakCallbackInfo<WeakCallbackDataType>& data)145   static void DisposeWeak(const WeakCallbackInfo<WeakCallbackDataType>& data) {}
146 
147  private:
148   template <typename T>
149   struct RemovePointer<T*> {
150     typedef T Type;
151   };
152 };
153 
154 
155 /**
156  * A map wrapper that allows using Global as a mapped value.
157  * C++11 embedders don't need this class, as they can use Global
158  * directly in std containers.
159  *
160  * The map relies on a backing map, whose type and accessors are described
161  * by the Traits class. The backing map will handle values of type
162  * PersistentContainerValue, with all conversion into and out of V8
163  * handles being transparently handled by this class.
164  */
165 template <typename K, typename V, typename Traits>
166 class PersistentValueMapBase {
167  public:
GetIsolate()168   Isolate* GetIsolate() { return isolate_; }
169 
170   /**
171    * Return size of the map.
172    */
Size()173   size_t Size() { return Traits::Size(&impl_); }
174 
175   /**
176    * Return whether the map holds weak persistents.
177    */
IsWeak()178   bool IsWeak() { return Traits::kCallbackType != kNotWeak; }
179 
180   /**
181    * Get value stored in map.
182    */
Get(const K& key)183   Local<V> Get(const K& key) {
184     V* p = FromVal(Traits::Get(&impl_, key));
185 #ifdef V8_ENABLE_DIRECT_LOCAL
186     if (p == nullptr) return Local<V>();
187 #endif
188     return Local<V>::New(isolate_, p);
189   }
190 
191   /**
192    * Check whether a value is contained in the map.
193    */
Contains(const K& key)194   bool Contains(const K& key) {
195     return Traits::Get(&impl_, key) != kPersistentContainerNotFound;
196   }
197 
198   /**
199    * Get value stored in map and set it in returnValue.
200    * Return true if a value was found.
201    */
SetReturnValue(const K& key, ReturnValue<Value> returnValue)202   bool SetReturnValue(const K& key,
203       ReturnValue<Value> returnValue) {
204     return SetReturnValueFromVal(&returnValue, Traits::Get(&impl_, key));
205   }
206 
207   /**
208    * Return value for key and remove it from the map.
209    */
Remove(const K& key)210   Global<V> Remove(const K& key) {
211     return Release(Traits::Remove(&impl_, key)).Pass();
212   }
213 
214   /**
215   * Traverses the map repeatedly,
216   * in case side effects of disposal cause insertions.
217   **/
Clear()218   void Clear() {
219     typedef typename Traits::Iterator It;
220     HandleScope handle_scope(isolate_);
221     // TODO(dcarney): figure out if this swap and loop is necessary.
222     while (!Traits::Empty(&impl_)) {
223       typename Traits::Impl impl;
224       Traits::Swap(impl_, impl);
225       for (It i = Traits::Begin(&impl); i != Traits::End(&impl); ++i) {
226         Traits::Dispose(isolate_, Release(Traits::Value(i)).Pass(),
227                         Traits::Key(i));
228       }
229     }
230   }
231 
232   /**
233    * Helper class for GetReference/SetWithReference. Do not use outside
234    * that context.
235    */
236   class PersistentValueReference {
237    public:
PersistentValueReference()238     PersistentValueReference() : value_(kPersistentContainerNotFound) { }
PersistentValueReference(const PersistentValueReference& other)239     PersistentValueReference(const PersistentValueReference& other)
240         : value_(other.value_) { }
241 
NewLocal(Isolate* isolate) const242     Local<V> NewLocal(Isolate* isolate) const {
243       return Local<V>::New(
244           isolate, internal::ValueHelper::SlotAsValue<V>(FromVal(value_)));
245     }
IsEmpty() const246     bool IsEmpty() const {
247       return value_ == kPersistentContainerNotFound;
248     }
249     template<typename T>
SetReturnValue(ReturnValue<T> returnValue)250     bool SetReturnValue(ReturnValue<T> returnValue) {
251       return SetReturnValueFromVal(&returnValue, value_);
252     }
Reset()253     void Reset() {
254       value_ = kPersistentContainerNotFound;
255     }
operator =(const PersistentValueReference& other)256     void operator=(const PersistentValueReference& other) {
257       value_ = other.value_;
258     }
259 
260    private:
261     friend class PersistentValueMapBase;
262     friend class PersistentValueMap<K, V, Traits>;
263     friend class GlobalValueMap<K, V, Traits>;
264 
PersistentValueReference(PersistentContainerValue value)265     explicit PersistentValueReference(PersistentContainerValue value)
266         : value_(value) { }
267 
operator =(PersistentContainerValue value)268     void operator=(PersistentContainerValue value) {
269       value_ = value;
270     }
271 
272     PersistentContainerValue value_;
273   };
274 
275   /**
276    * Get a reference to a map value. This enables fast, repeated access
277    * to a value stored in the map while the map remains unchanged.
278    *
279    * Careful: This is potentially unsafe, so please use with care.
280    * The value will become invalid if the value for this key changes
281    * in the underlying map, as a result of Set or Remove for the same
282    * key; as a result of the weak callback for the same key; or as a
283    * result of calling Clear() or destruction of the map.
284    */
GetReference(const K& key)285   PersistentValueReference GetReference(const K& key) {
286     return PersistentValueReference(Traits::Get(&impl_, key));
287   }
288 
289  protected:
PersistentValueMapBase(Isolate* isolate)290   explicit PersistentValueMapBase(Isolate* isolate)
291       : isolate_(isolate), label_(nullptr) {}
PersistentValueMapBase(Isolate* isolate, const char* label)292   PersistentValueMapBase(Isolate* isolate, const char* label)
293       : isolate_(isolate), label_(label) {}
294 
~PersistentValueMapBase()295   ~PersistentValueMapBase() { Clear(); }
296 
isolate()297   Isolate* isolate() { return isolate_; }
impl()298   typename Traits::Impl* impl() { return &impl_; }
299 
FromVal(PersistentContainerValue v)300   static V* FromVal(PersistentContainerValue v) {
301     return reinterpret_cast<V*>(v);
302   }
303 
ClearAndLeak(Global<V>* persistent)304   static PersistentContainerValue ClearAndLeak(Global<V>* persistent) {
305     V* v = persistent->template value<V>();
306     persistent->Clear();
307     return reinterpret_cast<PersistentContainerValue>(v);
308   }
309 
Leak(Global<V>* persistent)310   static PersistentContainerValue Leak(Global<V>* persistent) {
311     return reinterpret_cast<PersistentContainerValue>(persistent->slot());
312   }
313 
314   /**
315    * Return a container value as Global and make sure the weak
316    * callback is properly disposed of. All remove functionality should go
317    * through this.
318    */
Release(PersistentContainerValue v)319   static Global<V> Release(PersistentContainerValue v) {
320     Global<V> p;
321     p.slot() = reinterpret_cast<internal::Address*>(FromVal(v));
322     if (Traits::kCallbackType != kNotWeak && p.IsWeak()) {
323       Traits::DisposeCallbackData(
324           p.template ClearWeak<typename Traits::WeakCallbackDataType>());
325     }
326     return p.Pass();
327   }
328 
RemoveWeak(const K& key)329   void RemoveWeak(const K& key) {
330     Global<V> p;
331     p.slot() = reinterpret_cast<internal::Address*>(
332         FromVal(Traits::Remove(&impl_, key)));
333     p.Reset();
334   }
335 
AnnotateStrongRetainer(Global<V>* persistent)336   void AnnotateStrongRetainer(Global<V>* persistent) {
337     persistent->AnnotateStrongRetainer(label_);
338   }
339 
340  private:
341   PersistentValueMapBase(PersistentValueMapBase&);
342   void operator=(PersistentValueMapBase&);
343 
SetReturnValueFromVal(ReturnValue<Value>* returnValue, PersistentContainerValue value)344   static bool SetReturnValueFromVal(ReturnValue<Value>* returnValue,
345                                     PersistentContainerValue value) {
346     bool hasValue = value != kPersistentContainerNotFound;
347     if (hasValue) {
348       returnValue->SetInternal(
349           *reinterpret_cast<internal::Address*>(FromVal(value)));
350     }
351     return hasValue;
352   }
353 
354   Isolate* isolate_;
355   typename Traits::Impl impl_;
356   const char* label_;
357 };
358 
359 template <typename K, typename V, typename Traits>
360 class PersistentValueMap : public PersistentValueMapBase<K, V, Traits> {
361  public:
PersistentValueMap(Isolate* isolate)362   explicit PersistentValueMap(Isolate* isolate)
363       : PersistentValueMapBase<K, V, Traits>(isolate) {}
PersistentValueMap(Isolate* isolate, const char* label)364   PersistentValueMap(Isolate* isolate, const char* label)
365       : PersistentValueMapBase<K, V, Traits>(isolate, label) {}
366 
367   typedef
368       typename PersistentValueMapBase<K, V, Traits>::PersistentValueReference
369           PersistentValueReference;
370 
371   /**
372    * Put value into map. Depending on Traits::kIsWeak, the value will be held
373    * by the map strongly or weakly.
374    * Returns old value as Global.
375    */
Set(const K& key, Local<V> value)376   Global<V> Set(const K& key, Local<V> value) {
377     Global<V> persistent(this->isolate(), value);
378     return SetUnique(key, &persistent);
379   }
380 
381   /**
382    * Put value into map, like Set(const K&, Local<V>).
383    */
Set(const K& key, Global<V> value)384   Global<V> Set(const K& key, Global<V> value) {
385     return SetUnique(key, &value);
386   }
387 
388   /**
389    * Put the value into the map, and set the 'weak' callback when demanded
390    * by the Traits class.
391    */
SetUnique(const K& key, Global<V>* persistent)392   Global<V> SetUnique(const K& key, Global<V>* persistent) {
393     if (Traits::kCallbackType == kNotWeak) {
394       this->AnnotateStrongRetainer(persistent);
395     } else {
396       WeakCallbackType callback_type =
397           Traits::kCallbackType == kWeakWithInternalFields
398               ? WeakCallbackType::kInternalFields
399               : WeakCallbackType::kParameter;
400       auto value = Local<V>::New(this->isolate(), *persistent);
401       persistent->template SetWeak<typename Traits::WeakCallbackDataType>(
402           Traits::WeakCallbackParameter(this, key, value), WeakCallback,
403           callback_type);
404     }
405     PersistentContainerValue old_value =
406         Traits::Set(this->impl(), key, this->ClearAndLeak(persistent));
407     return this->Release(old_value).Pass();
408   }
409 
410   /**
411    * Put a value into the map and update the reference.
412    * Restrictions of GetReference apply here as well.
413    */
Set(const K& key, Global<V> value, PersistentValueReference* reference)414   Global<V> Set(const K& key, Global<V> value,
415                 PersistentValueReference* reference) {
416     *reference = this->Leak(&value);
417     return SetUnique(key, &value);
418   }
419 
420  private:
WeakCallback( const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data)421   static void WeakCallback(
422       const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data) {
423     if (Traits::kCallbackType != kNotWeak) {
424       PersistentValueMap<K, V, Traits>* persistentValueMap =
425           Traits::MapFromWeakCallbackInfo(data);
426       K key = Traits::KeyFromWeakCallbackInfo(data);
427       Traits::Dispose(data.GetIsolate(),
428                       persistentValueMap->Remove(key).Pass(), key);
429       Traits::DisposeCallbackData(data.GetParameter());
430     }
431   }
432 };
433 
434 
435 template <typename K, typename V, typename Traits>
436 class GlobalValueMap : public PersistentValueMapBase<K, V, Traits> {
437  public:
GlobalValueMap(Isolate* isolate)438   explicit GlobalValueMap(Isolate* isolate)
439       : PersistentValueMapBase<K, V, Traits>(isolate) {}
GlobalValueMap(Isolate* isolate, const char* label)440   GlobalValueMap(Isolate* isolate, const char* label)
441       : PersistentValueMapBase<K, V, Traits>(isolate, label) {}
442 
443   typedef
444       typename PersistentValueMapBase<K, V, Traits>::PersistentValueReference
445           PersistentValueReference;
446 
447   /**
448    * Put value into map. Depending on Traits::kIsWeak, the value will be held
449    * by the map strongly or weakly.
450    * Returns old value as Global.
451    */
Set(const K& key, Local<V> value)452   Global<V> Set(const K& key, Local<V> value) {
453     Global<V> persistent(this->isolate(), value);
454     return SetUnique(key, &persistent);
455   }
456 
457   /**
458    * Put value into map, like Set(const K&, Local<V>).
459    */
Set(const K& key, Global<V> value)460   Global<V> Set(const K& key, Global<V> value) {
461     return SetUnique(key, &value);
462   }
463 
464   /**
465    * Put the value into the map, and set the 'weak' callback when demanded
466    * by the Traits class.
467    */
SetUnique(const K& key, Global<V>* persistent)468   Global<V> SetUnique(const K& key, Global<V>* persistent) {
469     if (Traits::kCallbackType == kNotWeak) {
470       this->AnnotateStrongRetainer(persistent);
471     } else {
472       WeakCallbackType callback_type =
473           Traits::kCallbackType == kWeakWithInternalFields
474               ? WeakCallbackType::kInternalFields
475               : WeakCallbackType::kParameter;
476       auto value = Local<V>::New(this->isolate(), *persistent);
477       persistent->template SetWeak<typename Traits::WeakCallbackDataType>(
478           Traits::WeakCallbackParameter(this, key, value), OnWeakCallback,
479           callback_type);
480     }
481     PersistentContainerValue old_value =
482         Traits::Set(this->impl(), key, this->ClearAndLeak(persistent));
483     return this->Release(old_value).Pass();
484   }
485 
486   /**
487    * Put a value into the map and update the reference.
488    * Restrictions of GetReference apply here as well.
489    */
Set(const K& key, Global<V> value, PersistentValueReference* reference)490   Global<V> Set(const K& key, Global<V> value,
491                 PersistentValueReference* reference) {
492     *reference = this->Leak(&value);
493     return SetUnique(key, &value);
494   }
495 
496  private:
OnWeakCallback( const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data)497   static void OnWeakCallback(
498       const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data) {
499     if (Traits::kCallbackType != kNotWeak) {
500       auto map = Traits::MapFromWeakCallbackInfo(data);
501       K key = Traits::KeyFromWeakCallbackInfo(data);
502       map->RemoveWeak(key);
503       Traits::OnWeakCallback(data);
504       data.SetSecondPassCallback(SecondWeakCallback);
505     }
506   }
507 
SecondWeakCallback( const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data)508   static void SecondWeakCallback(
509       const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data) {
510     Traits::DisposeWeak(data);
511   }
512 };
513 
514 
515 /**
516  * A map that uses Global as value and std::map as the backing
517  * implementation. Persistents are held non-weak.
518  *
519  * C++11 embedders don't need this class, as they can use
520  * Global directly in std containers.
521  */
522 template<typename K, typename V,
523     typename Traits = DefaultPersistentValueMapTraits<K, V> >
524 class StdPersistentValueMap : public PersistentValueMap<K, V, Traits> {
525  public:
StdPersistentValueMap(Isolate* isolate)526   explicit StdPersistentValueMap(Isolate* isolate)
527       : PersistentValueMap<K, V, Traits>(isolate) {}
528 };
529 
530 
531 /**
532  * A map that uses Global as value and std::map as the backing
533  * implementation. Globals are held non-weak.
534  *
535  * C++11 embedders don't need this class, as they can use
536  * Global directly in std containers.
537  */
538 template <typename K, typename V,
539           typename Traits = DefaultGlobalMapTraits<K, V> >
540 class StdGlobalValueMap : public GlobalValueMap<K, V, Traits> {
541  public:
StdGlobalValueMap(Isolate* isolate)542   explicit StdGlobalValueMap(Isolate* isolate)
543       : GlobalValueMap<K, V, Traits>(isolate) {}
544 };
545 
546 class DefaultPersistentValueVectorTraits {
547  public:
548   typedef std::vector<PersistentContainerValue> Impl;
549 
Append(Impl* impl, PersistentContainerValue value)550   static void Append(Impl* impl, PersistentContainerValue value) {
551     impl->push_back(value);
552   }
IsEmpty(const Impl* impl)553   static bool IsEmpty(const Impl* impl) {
554     return impl->empty();
555   }
Size(const Impl* impl)556   static size_t Size(const Impl* impl) {
557     return impl->size();
558   }
Get(const Impl* impl, size_t i)559   static PersistentContainerValue Get(const Impl* impl, size_t i) {
560     return (i < impl->size()) ? impl->at(i) : kPersistentContainerNotFound;
561   }
ReserveCapacity(Impl* impl, size_t capacity)562   static void ReserveCapacity(Impl* impl, size_t capacity) {
563     impl->reserve(capacity);
564   }
Clear(Impl* impl)565   static void Clear(Impl* impl) {
566     impl->clear();
567   }
568 };
569 
570 /**
571  * A vector wrapper that safely stores Global values.
572  * C++11 embedders don't need this class, as they can use Global
573  * directly in std containers.
574  *
575  * This class relies on a backing vector implementation, whose type and methods
576  * are described by the Traits class. The backing map will handle values of type
577  * PersistentContainerValue, with all conversion into and out of V8
578  * handles being transparently handled by this class.
579  */
580 template <typename V, typename Traits = DefaultPersistentValueVectorTraits>
581 class V8_DEPRECATE_SOON("Use std::vector<Global<V>>.") PersistentValueVector {
582  public:
PersistentValueVector(Isolate* isolate)583   explicit PersistentValueVector(Isolate* isolate) : isolate_(isolate) { }
584 
~PersistentValueVector()585   ~PersistentValueVector() {
586     Clear();
587   }
588 
589   /**
590    * Append a value to the vector.
591    */
Append(Local<V> value)592   void Append(Local<V> value) {
593     Global<V> persistent(isolate_, value);
594     Traits::Append(&impl_, ClearAndLeak(&persistent));
595   }
596 
597   /**
598    * Append a persistent's value to the vector.
599    */
Append(Global<V> persistent)600   void Append(Global<V> persistent) {
601     Traits::Append(&impl_, ClearAndLeak(&persistent));
602   }
603 
604   /**
605    * Are there any values in the vector?
606    */
IsEmpty() const607   bool IsEmpty() const {
608     return Traits::IsEmpty(&impl_);
609   }
610 
611   /**
612    * How many elements are in the vector?
613    */
Size() const614   size_t Size() const {
615     return Traits::Size(&impl_);
616   }
617 
618   /**
619    * Retrieve the i-th value in the vector.
620    */
Get(size_t index) const621   Local<V> Get(size_t index) const {
622     return Local<V>::New(isolate_, internal::ValueHelper::SlotAsValue<V>(
623                                        FromVal(Traits::Get(&impl_, index))));
624   }
625 
626   /**
627    * Remove all elements from the vector.
628    */
Clear()629   void Clear() {
630     size_t length = Traits::Size(&impl_);
631     for (size_t i = 0; i < length; i++) {
632       Global<V> p;
633       p.slot() =
634           reinterpret_cast<internal::Address>(FromVal(Traits::Get(&impl_, i)));
635     }
636     Traits::Clear(&impl_);
637   }
638 
639   /**
640    * Reserve capacity in the vector.
641    * (Efficiency gains depend on the backing implementation.)
642    */
ReserveCapacity(size_t capacity)643   void ReserveCapacity(size_t capacity) {
644     Traits::ReserveCapacity(&impl_, capacity);
645   }
646 
647  private:
ClearAndLeak(Global<V>* persistent)648   static PersistentContainerValue ClearAndLeak(Global<V>* persistent) {
649     auto slot = persistent->slot();
650     persistent->Clear();
651     return reinterpret_cast<PersistentContainerValue>(slot);
652   }
653 
FromVal(PersistentContainerValue v)654   static V* FromVal(PersistentContainerValue v) {
655     return reinterpret_cast<V*>(v);
656   }
657 
658   Isolate* isolate_;
659   typename Traits::Impl impl_;
660 };
661 
662 }  // namespace v8
663 
664 #endif  // V8_UTIL_H
665