Implement PersistentValueVector, analogous to PersistentValueMap.
authordcarney@chromium.org <dcarney@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 31 Mar 2014 10:03:20 +0000 (10:03 +0000)
committerdcarney@chromium.org <dcarney@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 31 Mar 2014 10:03:20 +0000 (10:03 +0000)
BUG=
R=dcarney@chromium.org

Review URL: https://codereview.chromium.org/216973002

Patch from Daniel Vogelheim <vogelheim@chromium.org>.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20341 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

include/v8-util.h
include/v8.h
test/cctest/test-api.cc

index 219fe76aae6b328381b0f4e02d062c362a365335..accc6a49f6e7ff305d5cd002b159d69bac85630d 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "v8.h"
 #include <map>
+#include <vector>
 
 /**
  * Support for Persistent containers.
@@ -386,6 +387,123 @@ class StdPersistentValueMap : public PersistentValueMap<K, V, Traits> {
       : PersistentValueMap<K, V, Traits>(isolate) {}
 };
 
+
+class DefaultPersistentValueVectorTraits {
+ public:
+  typedef std::vector<PersistentContainerValue> Impl;
+
+  static void Append(Impl* impl, PersistentContainerValue value) {
+    impl->push_back(value);
+  }
+  static bool IsEmpty(const Impl* impl) {
+    return impl->empty();
+  }
+  static size_t Size(const Impl* impl) {
+    return impl->size();
+  }
+  static PersistentContainerValue Get(const Impl* impl, size_t i) {
+    return (i < impl->size()) ? impl->at(i) : kPersistentContainerNotFound;
+  }
+  static void ReserveCapacity(Impl* impl, size_t capacity) {
+    impl->reserve(capacity);
+  }
+  static void Clear(Impl* impl) {
+    impl->clear();
+  }
+};
+
+
+/**
+ * A vector wrapper that safely stores UniquePersistent values.
+ * C++11 embedders don't need this class, as they can use UniquePersistent
+ * directly in std containers.
+ *
+ * This class relies on a backing vector implementation, whose type and methods
+ * are described by the Traits class. The backing map will handle values of type
+ * PersistentContainerValue, with all conversion into and out of V8
+ * handles being transparently handled by this class.
+ */
+template<typename V, typename Traits = DefaultPersistentValueVectorTraits>
+class PersistentValueVector {
+ public:
+  explicit PersistentValueVector(Isolate* isolate) : isolate_(isolate) { }
+
+  ~PersistentValueVector() {
+    Clear();
+  }
+
+  /**
+   * Append a value to the vector.
+   */
+  void Append(Local<V> value) {
+    UniquePersistent<V> persistent(isolate_, value);
+    Traits::Append(&impl_, ClearAndLeak(&persistent));
+  }
+
+  /**
+   * Append a persistent's value to the vector.
+   */
+  void Append(UniquePersistent<V> persistent) {
+    Traits::Append(&impl_, ClearAndLeak(&persistent));
+  };
+
+  /**
+   * Are there any values in the vector?
+   */
+  bool IsEmpty() const {
+    return Traits::IsEmpty(&impl_);
+  }
+
+  /**
+   * How many elements are in the vector?
+   */
+  size_t Size() const {
+    return Traits::Size(&impl_);
+  }
+
+  /**
+   * Retrieve the i-th value in the vector.
+   */
+  Local<V> Get(size_t index) const {
+    return Local<V>::New(isolate_, FromVal(Traits::Get(&impl_, index)));
+  }
+
+  /**
+   * Remove all elements from the vector.
+   */
+  void Clear() {
+    size_t length = Traits::Size(&impl_);
+    for (size_t i = 0; i < length; i++) {
+      UniquePersistent<V> p;
+      p.val_ = FromVal(Traits::Get(&impl_, i));
+    }
+    Traits::Clear(&impl_);
+  }
+
+  /**
+   * Reserve capacity in the vector.
+   * (Efficiency gains depend on the backing implementation.)
+   */
+  void ReserveCapacity(size_t capacity) {
+    Traits::ReserveCapacity(&impl_, capacity);
+  }
+
+ private:
+  static PersistentContainerValue ClearAndLeak(
+      UniquePersistent<V>* persistent) {
+    V* v = persistent->val_;
+    persistent->val_ = 0;
+    return reinterpret_cast<PersistentContainerValue>(v);
+  }
+
+  static V* FromVal(PersistentContainerValue v) {
+    return reinterpret_cast<V*>(v);
+  }
+
+  Isolate* isolate_;
+  typename Traits::Impl impl_;
+};
+
 }  // namespace v8
 
 #endif  // V8_UTIL_H_
index 608e3c52c348ec5a39da65f75503c27abf79b44e..5f5e08d190f4be227c2e46a04557d4661391534d 100644 (file)
@@ -129,6 +129,7 @@ template<class T,
          class M = NonCopyablePersistentTraits<T> > class Persistent;
 template<class T> class UniquePersistent;
 template<class K, class V, class T> class PersistentValueMap;
+template<class V, class T> class PersistentValueVector;
 template<class T, class P> class WeakCallbackObject;
 class FunctionTemplate;
 class ObjectTemplate;
@@ -417,6 +418,7 @@ template <class T> class Local : public Handle<T> {
   friend class HandleScope;
   friend class EscapableHandleScope;
   template<class F1, class F2, class F3> friend class PersistentValueMap;
+  template<class F1, class F2> friend class PersistentValueVector;
 
   V8_INLINE static Local<T> New(Isolate* isolate, T* that);
 };
@@ -586,6 +588,7 @@ template <class T> class PersistentBase {
   template<class F> friend class PersistentBase;
   template<class F> friend class ReturnValue;
   template<class F1, class F2, class F3> friend class PersistentValueMap;
+  template<class F1, class F2> friend class PersistentValueVector;
   friend class Object;
 
   explicit V8_INLINE PersistentBase(T* val) : val_(val) {}
index 9a67faea493b3bc39b51a399f13090c5a3f011d0..9e8302bb786c53f5c294a192a7a2605af04cc5b3 100644 (file)
@@ -3592,6 +3592,49 @@ TEST(PersistentValueMap) {
 }
 
 
+TEST(PersistentValueVector) {
+  LocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::internal::GlobalHandles* global_handles =
+      reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
+  int handle_count = global_handles->global_handles_count();
+  HandleScope scope(isolate);
+
+  v8::PersistentValueVector<v8::Object> vector(isolate);
+
+  Local<v8::Object> obj1 = v8::Object::New(isolate);
+  Local<v8::Object> obj2 = v8::Object::New(isolate);
+  v8::UniquePersistent<v8::Object> obj3(isolate, v8::Object::New(isolate));
+
+  CHECK(vector.IsEmpty());
+  CHECK_EQ(0, static_cast<int>(vector.Size()));
+
+  vector.ReserveCapacity(3);
+  CHECK(vector.IsEmpty());
+
+  vector.Append(obj1);
+  vector.Append(obj2);
+  vector.Append(obj1);
+  vector.Append(obj3.Pass());
+  vector.Append(obj1);
+
+  CHECK(!vector.IsEmpty());
+  CHECK_EQ(5, static_cast<int>(vector.Size()));
+  CHECK(obj3.IsEmpty());
+  CHECK_EQ(obj1, vector.Get(0));
+  CHECK_EQ(obj1, vector.Get(2));
+  CHECK_EQ(obj1, vector.Get(4));
+  CHECK_EQ(obj2, vector.Get(1));
+
+  CHECK_EQ(5 + handle_count, global_handles->global_handles_count());
+
+  vector.Clear();
+  CHECK(vector.IsEmpty());
+  CHECK_EQ(0, static_cast<int>(vector.Size()));
+  CHECK_EQ(handle_count, global_handles->global_handles_count());
+}
+
+
 THREADED_TEST(GlobalHandleUpcast) {
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);