From 8b304a683215a264c3dae3f659904d05d2ebadee Mon Sep 17 00:00:00 2001 From: "dcarney@chromium.org" Date: Mon, 31 Mar 2014 10:03:20 +0000 Subject: [PATCH] Implement PersistentValueVector, analogous to PersistentValueMap. BUG= R=dcarney@chromium.org Review URL: https://codereview.chromium.org/216973002 Patch from Daniel Vogelheim . git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20341 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- include/v8-util.h | 118 ++++++++++++++++++++++++++++++++++++++++ include/v8.h | 3 + test/cctest/test-api.cc | 43 +++++++++++++++ 3 files changed, 164 insertions(+) diff --git a/include/v8-util.h b/include/v8-util.h index 219fe76aae..accc6a49f6 100644 --- a/include/v8-util.h +++ b/include/v8-util.h @@ -30,6 +30,7 @@ #include "v8.h" #include +#include /** * Support for Persistent containers. @@ -386,6 +387,123 @@ class StdPersistentValueMap : public PersistentValueMap { : PersistentValueMap(isolate) {} }; + +class DefaultPersistentValueVectorTraits { + public: + typedef std::vector 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 +class PersistentValueVector { + public: + explicit PersistentValueVector(Isolate* isolate) : isolate_(isolate) { } + + ~PersistentValueVector() { + Clear(); + } + + /** + * Append a value to the vector. + */ + void Append(Local value) { + UniquePersistent persistent(isolate_, value); + Traits::Append(&impl_, ClearAndLeak(&persistent)); + } + + /** + * Append a persistent's value to the vector. + */ + void Append(UniquePersistent 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 Get(size_t index) const { + return Local::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 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* persistent) { + V* v = persistent->val_; + persistent->val_ = 0; + return reinterpret_cast(v); + } + + static V* FromVal(PersistentContainerValue v) { + return reinterpret_cast(v); + } + + Isolate* isolate_; + typename Traits::Impl impl_; +}; + } // namespace v8 #endif // V8_UTIL_H_ diff --git a/include/v8.h b/include/v8.h index 608e3c52c3..5f5e08d190 100644 --- a/include/v8.h +++ b/include/v8.h @@ -129,6 +129,7 @@ template > class Persistent; template class UniquePersistent; template class PersistentValueMap; +template class PersistentValueVector; template class WeakCallbackObject; class FunctionTemplate; class ObjectTemplate; @@ -417,6 +418,7 @@ template class Local : public Handle { friend class HandleScope; friend class EscapableHandleScope; template friend class PersistentValueMap; + template friend class PersistentValueVector; V8_INLINE static Local New(Isolate* isolate, T* that); }; @@ -586,6 +588,7 @@ template class PersistentBase { template friend class PersistentBase; template friend class ReturnValue; template friend class PersistentValueMap; + template friend class PersistentValueVector; friend class Object; explicit V8_INLINE PersistentBase(T* val) : val_(val) {} diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index 9a67faea49..9e8302bb78 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -3592,6 +3592,49 @@ TEST(PersistentValueMap) { } +TEST(PersistentValueVector) { + LocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::internal::GlobalHandles* global_handles = + reinterpret_cast(isolate)->global_handles(); + int handle_count = global_handles->global_handles_count(); + HandleScope scope(isolate); + + v8::PersistentValueVector vector(isolate); + + Local obj1 = v8::Object::New(isolate); + Local obj2 = v8::Object::New(isolate); + v8::UniquePersistent obj3(isolate, v8::Object::New(isolate)); + + CHECK(vector.IsEmpty()); + CHECK_EQ(0, static_cast(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(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(vector.Size())); + CHECK_EQ(handle_count, global_handles->global_handles_count()); +} + + THREADED_TEST(GlobalHandleUpcast) { v8::Isolate* isolate = CcTest::isolate(); v8::HandleScope scope(isolate);