diff --git a/atom.gyp b/atom.gyp index 2a1c6e173bb..4b67a4dd843 100644 --- a/atom.gyp +++ b/atom.gyp @@ -12,6 +12,7 @@ 'browser/atom/atom.coffee', 'browser/atom/objects_registry.coffee', 'browser/atom/rpc_server.coffee', + 'common/api/lib/id_weak_map.coffee', 'renderer/api/lib/ipc.coffee', 'renderer/api/lib/remote.coffee', ], @@ -44,6 +45,8 @@ 'common/api/api_messages.cc', 'common/api/api_messages.h', 'common/api/atom_api_idle_gc.cc', + 'common/api/atom_api_id_weak_map.cc', + 'common/api/atom_api_id_weak_map.h', 'common/api/atom_api_v8_util.cc', 'common/api/atom_bindings.cc', 'common/api/atom_bindings.h', diff --git a/common/api/atom_api_id_weak_map.cc b/common/api/atom_api_id_weak_map.cc new file mode 100644 index 00000000000..1680024d46e --- /dev/null +++ b/common/api/atom_api_id_weak_map.cc @@ -0,0 +1,138 @@ +// Copyright (c) 2013 GitHub, Inc. All rights reserved. +// Copyright (c) 2012 Intel Corp. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "common/api/atom_api_id_weak_map.h" + +namespace atom { + +namespace api { + +IDWeakMap::IDWeakMap() + : nextId_(0) { +} + +IDWeakMap::~IDWeakMap() { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + + auto copied_map = map_; + for (auto el : copied_map) + Erase(isolate, el.first); +} + +bool IDWeakMap::Has(int key) const { + return map_.find(key) != map_.end(); +} + +void IDWeakMap::Erase(v8::Isolate* isolate, int key) { + v8::Persistent value = map_[key]; + value.ClearWeak(isolate); + value.Dispose(isolate); + value.Clear(); + + map_.erase(key); +} + +int IDWeakMap::GetNextID() { + return ++nextId_; +} + +// static +void IDWeakMap::WeakCallback(v8::Isolate* isolate, + v8::Persistent value, + void *data) { + IDWeakMap* obj = static_cast(data); + int key = value->ToObject()->GetHiddenValue( + v8::String::New("IDWeakMapKey"))->IntegerValue(); + obj->Erase(isolate, key); +} + +// static +v8::Handle IDWeakMap::New(const v8::Arguments& args) { + IDWeakMap* obj = new IDWeakMap(); + obj->Wrap(args.This()); + return args.This(); +} + +// static +v8::Handle IDWeakMap::Add(const v8::Arguments& args) { + if (!args[0]->IsObject()) + return node::ThrowTypeError("Bad argument"); + + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + IDWeakMap* obj = ObjectWrap::Unwrap(args.This()); + int key = obj->GetNextID(); + + v8::Handle v8_key = v8::Integer::New(key); + v8::Persistent value = + v8::Persistent::New(isolate, args[0]); + + value->ToObject()->SetHiddenValue(v8::String::New("IDWeakMapKey"), v8_key); + value.MakeWeak(isolate, obj, WeakCallback); + obj->map_[key] = value; + + return v8_key; +} + +// static +v8::Handle IDWeakMap::Get(const v8::Arguments& args) { + if (!args[0]->IsNumber()) + return node::ThrowTypeError("Bad argument"); + + IDWeakMap* obj = ObjectWrap::Unwrap(args.This()); + + int key = args[0]->IntegerValue(); + if (!obj->Has(key)) + return node::ThrowError("Invalid key"); + + return obj->map_[key]; +} + +// static +v8::Handle IDWeakMap::Has(const v8::Arguments& args) { + if (!args[0]->IsNumber()) + return node::ThrowTypeError("Bad argument"); + + IDWeakMap* obj = ObjectWrap::Unwrap(args.This()); + + int key = args[0]->IntegerValue(); + return v8::Boolean::New(obj->Has(key)); +} + +// static +v8::Handle IDWeakMap::Remove(const v8::Arguments& args) { + if (!args[0]->IsNumber()) + return node::ThrowTypeError("Bad argument"); + + IDWeakMap* obj = ObjectWrap::Unwrap(args.This()); + + int key = args[0]->IntegerValue(); + if (!obj->Has(key)) + return node::ThrowError("Invalid key"); + + obj->Erase(v8::Isolate::GetCurrent(), key); + return v8::Undefined(); +} + +// static +void IDWeakMap::Initialize(v8::Handle target) { + v8::HandleScope scope; + + v8::Local t = v8::FunctionTemplate::New(IDWeakMap::New); + t->InstanceTemplate()->SetInternalFieldCount(1); + t->SetClassName(v8::String::NewSymbol("IDWeakMap")); + + NODE_SET_PROTOTYPE_METHOD(t, "add", Add); + NODE_SET_PROTOTYPE_METHOD(t, "get", Get); + NODE_SET_PROTOTYPE_METHOD(t, "has", Has); + NODE_SET_PROTOTYPE_METHOD(t, "remove", Remove); + + target->Set(v8::String::NewSymbol("IDWeakMap"), t->GetFunction()); +} + +} // namespace api + +} // namespace atom + +NODE_MODULE(atom_common_id_weak_map, atom::api::IDWeakMap::Initialize) diff --git a/common/api/atom_api_id_weak_map.h b/common/api/atom_api_id_weak_map.h new file mode 100644 index 00000000000..ec28d57f4ee --- /dev/null +++ b/common/api/atom_api_id_weak_map.h @@ -0,0 +1,51 @@ +// Copyright (c) 2013 GitHub, Inc. All rights reserved. +// Copyright (c) 2012 Intel Corp. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_API_ATOM_API_ID_WEAK_MAP_H_ +#define ATOM_BROWSER_API_ATOM_API_ID_WEAK_MAP_H_ + +#include + +#include "base/basictypes.h" +#include "vendor/node/src/node_object_wrap.h" + +namespace atom { + +namespace api { + +class IDWeakMap : public node::ObjectWrap { + public: + static void Initialize(v8::Handle target); + + private: + IDWeakMap(); + virtual ~IDWeakMap(); + + bool Has(int key) const; + void Erase(v8::Isolate* isolate, int key); + int GetNextID(); + + static void WeakCallback(v8::Isolate* isolate, + v8::Persistent value, + void *data); + + static v8::Handle New(const v8::Arguments& args); + static v8::Handle Add(const v8::Arguments& args); + static v8::Handle Get(const v8::Arguments& args); + static v8::Handle Has(const v8::Arguments& args); + static v8::Handle Remove(const v8::Arguments& args); + + int nextId_; + + std::map> map_; + + DISALLOW_COPY_AND_ASSIGN(IDWeakMap); +}; + +} // namespace api + +} // namespace atom + +#endif // ATOM_BROWSER_API_ATOM_API_ID_WEAK_MAP_H_ diff --git a/common/api/atom_extensions.h b/common/api/atom_extensions.h index 6e75609609b..4967dd48094 100644 --- a/common/api/atom_extensions.h +++ b/common/api/atom_extensions.h @@ -19,6 +19,7 @@ NODE_EXT_LIST_ITEM(atom_renderer_ipc) // Module names start with `atom_common_` can be used by both browser and // renderer processes. NODE_EXT_LIST_ITEM(atom_common_idle_gc) +NODE_EXT_LIST_ITEM(atom_common_id_weak_map) NODE_EXT_LIST_ITEM(atom_common_v8_util) NODE_EXT_LIST_END diff --git a/common/api/lib/id_weak_map.coffee b/common/api/lib/id_weak_map.coffee new file mode 100644 index 00000000000..4860a3e89ac --- /dev/null +++ b/common/api/lib/id_weak_map.coffee @@ -0,0 +1,3 @@ +IDWeakMap = process.atom_binding('id_weak_map').IDWeakMap + +module.exports = IDWeakMap