// 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" #include "base/logging.h" namespace atom { namespace api { IDWeakMap::IDWeakMap() : next_id_(0) { } IDWeakMap::~IDWeakMap() { v8::Isolate* isolate = v8::Isolate::GetCurrent(); auto copied_map = map_; for (auto el = copied_map.begin(); el != copied_map.end(); ++el) Erase(isolate, el->first); } bool IDWeakMap::Has(int key) const { return map_.find(key) != map_.end(); } void IDWeakMap::Erase(v8::Isolate* isolate, int key) { if (!Has(key)) { LOG(WARNING) << "Object with key " << key << " is being GCed for twice."; return; } v8::Persistent value = map_[key]; value.ClearWeak(isolate); value.Dispose(isolate); value.Clear(); map_.erase(key); } int IDWeakMap::GetNextID() { return ++next_id_; } // static void IDWeakMap::WeakCallback(v8::Isolate* isolate, v8::Persistent value, void *data) { v8::HandleScope scope; 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::Keys(const v8::Arguments& args) { IDWeakMap* obj = ObjectWrap::Unwrap(args.This()); v8::Handle keys = v8::Array::New(obj->map_.size()); int i = 0; for (auto el = obj->map_.begin(); el != obj->map_.end(); ++el) { keys->Set(i, v8::Integer::New(el->first)); ++i; } return keys; } // 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, "keys", Keys); 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)