Implement PersistentValueVector, analogous to PersistentValueMap.
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
This commit is contained in:
parent
a2f82479c4
commit
8b304a6832
@ -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_
|
||||
|
@ -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) {}
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user