From e7a197232ff6d72ea77894e4d193012b54f3a6e3 Mon Sep 17 00:00:00 2001 From: Luis Blanco Date: Mon, 19 Mar 2018 23:01:17 +0300 Subject: [PATCH] emitter new inheritance --- examples/node-addon/cpp/example.cpp | 26 ++- examples/node-addon/cpp/example.hpp | 13 +- include/event-emitter.hpp | 247 ++++++++++++++++++---------- package.json | 2 +- 4 files changed, 179 insertions(+), 109 deletions(-) diff --git a/examples/node-addon/cpp/example.cpp b/examples/node-addon/cpp/example.cpp index aa2834f..33a3f77 100644 --- a/examples/node-addon/cpp/example.cpp +++ b/examples/node-addon/cpp/example.cpp @@ -1,6 +1,8 @@ #include #include +#include + #include "example.hpp" using namespace v8; @@ -10,10 +12,14 @@ using namespace std; #define THIS_EXAMPLE \ Example *example = ObjectWrap::Unwrap(info.This()); +#define THIS_EVENT_EMITTER \ + EventEmitter *eventEmitter = ObjectWrap::Unwrap(info.This()); + #define THIS_CHECK \ if (example->_isDestroyed) return; +Nan::Persistent Example::_prototype; Nan::Persistent Example::_constructor; @@ -21,15 +27,17 @@ void Example::init(Handle target) { Local proto = Nan::New(newCtor); + // class Example extends EventEmitter + Local parent = Nan::New(EventEmitter::_prototype); + proto->Inherit(parent); + + proto->InstanceTemplate()->SetInternalFieldCount(1); proto->SetClassName(JS_STR("Example")); // -------- dynamic - // Add EventEmitter methods - extendPrototype(proto); - Nan::SetPrototypeMethod(proto, "destroy", destroy); @@ -37,10 +45,10 @@ void Example::init(Handle target) { Local ctor = Nan::GetFunction(proto).ToLocalChecked(); - extendConstructor(ctor); - + _prototype.Reset(proto); _constructor.Reset(ctor); + Nan::Set(target, JS_STR("Example"), ctor); } @@ -48,7 +56,8 @@ void Example::init(Handle target) { NAN_METHOD(Example::newCtor) { - CTOR_CHECK("Example"); + v8::Local superCtor = Nan::New(EventEmitter::_constructor); + superCtor->Call(info.This(), 0, nullptr); Example *example = new Example(); example->Wrap(info.This()); @@ -76,13 +85,12 @@ void Example::_destroy() { DES_CHECK; _isDestroyed = true; - emit("destroy"); - } -NAN_METHOD(Example::destroy) { THIS_EXAMPLE; THIS_CHECK; +NAN_METHOD(Example::destroy) { THIS_EXAMPLE; THIS_CHECK; THIS_EVENT_EMITTER; + eventEmitter->_destroy(); example->_destroy(); } diff --git a/examples/node-addon/cpp/example.hpp b/examples/node-addon/cpp/example.hpp index c2bb23a..c5773f3 100644 --- a/examples/node-addon/cpp/example.hpp +++ b/examples/node-addon/cpp/example.hpp @@ -2,36 +2,33 @@ #define _EXAMPLE_HPP_ -#include +#include #include "common.hpp" -class Example : public EventEmitter { +class Example : public Nan::ObjectWrap { public: static void init(v8::Handle target); - virtual ~Example(); - -protected: +private: Example(); + virtual ~Example(); static NAN_METHOD(newCtor); static NAN_METHOD(destroy); - -private: - void _destroy(); private: + static Nan::Persistent _prototype; static Nan::Persistent _constructor; bool _isDestroyed; diff --git a/include/event-emitter.hpp b/include/event-emitter.hpp index d920fcf..7c5f6a7 100644 --- a/include/event-emitter.hpp +++ b/include/event-emitter.hpp @@ -9,11 +9,27 @@ #include // -> std::cout << "..." << std::endl; -#define THIS_EMITTER \ - EventEmitter *emitter = ObjectWrap::Unwrap(info.This()); +#define THIS_EVENT_EMITTER \ + EventEmitter *eventEmitter = ObjectWrap::Unwrap(info.This()); + +#define EVENT_EMITTER_THIS_CHECK \ + if (eventEmitter->_isDestroyed) return; + +#define EVENT_EMITTER_DES_CHECK \ + if (_isDestroyed) return; -class EventEmitter : public Nan::ObjectWrap { +template +struct StaticHolder { + static Nan::Persistent _prototype; + static Nan::Persistent _constructor; +}; + +template Nan::Persistent StaticHolder::_prototype; +template Nan::Persistent StaticHolder::_constructor; + + +class EventEmitter : public StaticHolder, public Nan::ObjectWrap { typedef Nan::CopyablePersistentTraits::CopyablePersistent FN_TYPE; typedef std::deque VEC_TYPE; @@ -23,18 +39,23 @@ class EventEmitter : public Nan::ObjectWrap { typedef MAP_TYPE::iterator MAP_IT_TYPE; typedef FNMAP_TYPE::iterator FNMAP_IT_TYPE; +// Public V8 init +public: -protected: - - EventEmitter () { - _maxListeners = 0; - _freeId = 0; - } - - virtual ~EventEmitter () {} - - - static void extendPrototype(v8::Local &proto) { + static void init(v8::Local target) { + + v8::Local proto = Nan::New(newCtor); + + proto->InstanceTemplate()->SetInternalFieldCount(1); + proto->SetClassName(JS_STR("EventEmitter")); + + + // Accessors + v8::Local obj = proto->PrototypeTemplate(); + ACCESSOR_R(obj, isDestroyed); + + + // -------- dynamic Nan::SetPrototypeMethod(proto, "listenerCount", jsListenerCount); Nan::SetPrototypeMethod(proto, "addListener", jsAddListener); @@ -51,20 +72,23 @@ protected: Nan::SetPrototypeMethod(proto, "setMaxListeners", jsSetMaxListeners); Nan::SetPrototypeMethod(proto, "rawListeners", jsRawListeners); - } - - - static void extendConstructor(v8::Local &ctorFn) { + // -------- static - v8::Local ctor = v8::Local::Cast(ctorFn); + v8::Local ctor = Nan::GetFunction(proto).ToLocalChecked(); - Nan::SetMethod(ctor, "listenerCount", jsStaticListenerCount); + v8::Local ctorObj = v8::Local::Cast(ctor); + + Nan::SetMethod(ctorObj, "listenerCount", jsStaticListenerCount); + + + _constructor.Reset(ctor); + _prototype.Reset(proto); + + Nan::Set(target, JS_STR("EventEmitter"), ctor); } -public: - // C++ side emit() method void emit(const std::string &name, int argc = 0, v8::Local *argv = NULL) { @@ -112,16 +136,55 @@ public: } -protected: + void _destroy() { EVENT_EMITTER_DES_CHECK; + _isDestroyed = true; + emit("destroy"); + } + + +private: + + EventEmitter () { + _isDestroyed = false; + _maxListeners = 0; + _freeId = 0; + } + + virtual ~EventEmitter () { _destroy(); } + + + static NAN_METHOD(newCtor) { + + EventEmitter *eventEmitter = new EventEmitter(); + eventEmitter->Wrap(info.This()); + + RET_VALUE(info.This()); + + } + + + static NAN_GETTER(isDestroyedGetter) { THIS_EVENT_EMITTER; + + RET_VALUE(JS_BOOL(eventEmitter->_isDestroyed)); + + } + + + NAN_METHOD(destroy) { THIS_EVENT_EMITTER; EVENT_EMITTER_THIS_CHECK; + + eventEmitter->_destroy(); + + } + // Deprecated static method static NAN_METHOD(jsStaticListenerCount) { REQ_OBJ_ARG(0, obj); - EventEmitter *emitter = ObjectWrap::Unwrap(obj); + EventEmitter *eventEmitter = ObjectWrap::Unwrap(obj); REQ_UTF8_ARG(1, name); - const VEC_TYPE &list = emitter->_listeners[*name]; + const VEC_TYPE &list = eventEmitter->_listeners[*name]; RET_VALUE(JS_INT(static_cast(list.size()))); @@ -131,7 +194,7 @@ protected: static NAN_METHOD(jsAddListener) { _wrapListener(info); } - static NAN_METHOD(jsEmit) { THIS_EMITTER; + static NAN_METHOD(jsEmit) { THIS_EVENT_EMITTER; REQ_UTF8_ARG(0, name); @@ -143,22 +206,22 @@ protected: args.push_back(info[i]); } - emitter->emit(*name, length - 1, &args[0]); + eventEmitter->emit(*name, length - 1, &args[0]); } - static NAN_METHOD(jsEventNames) { THIS_EMITTER; + static NAN_METHOD(jsEventNames) { THIS_EVENT_EMITTER; - v8::Local jsNames = Nan::New(emitter->_raw.size()); + v8::Local jsNames = Nan::New(eventEmitter->_raw.size()); - if (emitter->_raw.empty()) { + if (eventEmitter->_raw.empty()) { RET_VALUE(jsNames); return; } int i = 0; - for (MAP_IT_TYPE it = emitter->_raw.begin(); it != emitter->_raw.end(); ++it, i++) { + for (MAP_IT_TYPE it = eventEmitter->_raw.begin(); it != eventEmitter->_raw.end(); ++it, i++) { jsNames->Set(JS_INT(i), JS_STR(it->first)); @@ -169,29 +232,29 @@ protected: } - static NAN_METHOD(jsGetMaxListeners) { THIS_EMITTER; + static NAN_METHOD(jsGetMaxListeners) { THIS_EVENT_EMITTER; - RET_VALUE(JS_INT(emitter->_maxListeners)); + RET_VALUE(JS_INT(eventEmitter->_maxListeners)); } - static NAN_METHOD(jsListenerCount) { THIS_EMITTER; + static NAN_METHOD(jsListenerCount) { THIS_EVENT_EMITTER; REQ_UTF8_ARG(0, name); - const VEC_TYPE &list = emitter->_listeners[*name]; + const VEC_TYPE &list = eventEmitter->_listeners[*name]; RET_VALUE(JS_INT(static_cast(list.size()))); } - static NAN_METHOD(jsListeners) { THIS_EMITTER; + static NAN_METHOD(jsListeners) { THIS_EVENT_EMITTER; REQ_UTF8_ARG(0, name); - VEC_TYPE &list = emitter->_listeners[*name]; + VEC_TYPE &list = eventEmitter->_listeners[*name]; v8::Local jsListeners = Nan::New(list.size()); @@ -217,25 +280,25 @@ protected: const std::string &name, Nan::Persistent &cb, bool isFront - ) { THIS_EMITTER; + ) { THIS_EVENT_EMITTER; v8::Local args[] = { info[0], info[1] }; - emitter->emit("newListener", 2, args); + eventEmitter->emit("newListener", 2, args); if (isFront) { - emitter->_listeners[name].push_front(cb); - emitter->_raw[name].push_front(cb); + eventEmitter->_listeners[name].push_front(cb); + eventEmitter->_raw[name].push_front(cb); } else { - emitter->_listeners[name].push_back(cb); - emitter->_raw[name].push_back(cb); + eventEmitter->_listeners[name].push_back(cb); + eventEmitter->_raw[name].push_back(cb); } - int count = emitter->_raw[name].size(); + int count = eventEmitter->_raw[name].size(); - if (emitter->_maxListeners > 0 && count > emitter->_maxListeners) { + if (eventEmitter->_maxListeners > 0 && count > eventEmitter->_maxListeners) { std::cout << "EventEmitter Warning: too many listeners ("; - std::cout << count << " > " << emitter->_maxListeners << ") on '"; + std::cout << count << " > " << eventEmitter->_maxListeners << ") on '"; std::cout << name << "' event, possible memory leak." << std::endl; // Some JS magic to retrieve the call stack @@ -275,29 +338,29 @@ protected: Nan::Persistent &raw, Nan::Persistent &cb, bool isFront - ) { THIS_EMITTER; + ) { THIS_EVENT_EMITTER; v8::Local args[] = { info[0], info[1] }; - emitter->emit("newListener", 2, args); + eventEmitter->emit("newListener", 2, args); if (isFront) { - emitter->_listeners[name].push_front(cb); - emitter->_raw[name].push_front(raw); + eventEmitter->_listeners[name].push_front(cb); + eventEmitter->_raw[name].push_front(raw); } else { - emitter->_listeners[name].push_back(cb); - emitter->_raw[name].push_back(raw); + eventEmitter->_listeners[name].push_back(cb); + eventEmitter->_raw[name].push_back(raw); } - int nextId = emitter->_freeId++; - emitter->_wrappedIds[nextId] = cb; - emitter->_rawIds[nextId] = raw; + int nextId = eventEmitter->_freeId++; + eventEmitter->_wrappedIds[nextId] = cb; + eventEmitter->_rawIds[nextId] = raw; - int count = emitter->_raw[name].size(); + int count = eventEmitter->_raw[name].size(); - if (emitter->_maxListeners > 0 && count > emitter->_maxListeners) { + if (eventEmitter->_maxListeners > 0 && count > eventEmitter->_maxListeners) { std::cout << "EventEmitter Warning: too many listeners ("; - std::cout << count << " > " << emitter->_maxListeners << ") on '"; + std::cout << count << " > " << eventEmitter->_maxListeners << ") on '"; std::cout << name << "' event, possible memory leak." << std::endl; // Some JS magic to retrieve the call stack @@ -355,16 +418,16 @@ protected: static NAN_METHOD(jsPrependOnceListener) { _wrapOnceListener(info, true); } - static NAN_METHOD(jsRemoveAllListeners) { THIS_EMITTER; + static NAN_METHOD(jsRemoveAllListeners) { THIS_EVENT_EMITTER; if (info.Length() > 0 && info[0]->IsString()) { - MAP_TYPE tmpMap = emitter->_raw; + MAP_TYPE tmpMap = eventEmitter->_raw; - emitter->_listeners.clear(); - emitter->_raw.clear(); - emitter->_wrappedIds.clear(); - emitter->_rawIds.clear(); + eventEmitter->_listeners.clear(); + eventEmitter->_raw.clear(); + eventEmitter->_wrappedIds.clear(); + eventEmitter->_rawIds.clear(); for (MAP_IT_TYPE itMap = tmpMap.begin(); itMap != tmpMap.end(); ++itMap) { @@ -374,7 +437,7 @@ protected: for (IT_TYPE it = list.begin(); it != list.end(); ++it) { v8::Local args[] = { JS_STR(current.c_str()), Nan::New(*it) }; - emitter->emit("removeListener", 2, args); + eventEmitter->emit("removeListener", 2, args); } @@ -387,13 +450,13 @@ protected: REQ_UTF8_ARG(0, n); std::string name = std::string(*n); - VEC_TYPE &list = emitter->_raw[name]; + VEC_TYPE &list = eventEmitter->_raw[name]; if (list.empty()) { return; } - if (emitter->_rawIds.size()) { + if (eventEmitter->_rawIds.size()) { std::vector removes; @@ -401,7 +464,7 @@ protected: FN_TYPE fn = *it; - for (FNMAP_IT_TYPE itRaw = emitter->_rawIds.begin(); itRaw != emitter->_rawIds.end(); ++itRaw) { + for (FNMAP_IT_TYPE itRaw = eventEmitter->_rawIds.begin(); itRaw != eventEmitter->_rawIds.end(); ++itRaw) { if (fn == itRaw->second) { removes.push_back(itRaw->first); } @@ -412,8 +475,8 @@ protected: if (removes.size()) { for (std::vector::const_iterator it = removes.begin(); it != removes.end(); ++it) { - emitter->_wrappedIds.erase(*it); - emitter->_rawIds.erase(*it); + eventEmitter->_wrappedIds.erase(*it); + eventEmitter->_rawIds.erase(*it); } } @@ -421,22 +484,22 @@ protected: } - VEC_TYPE tmpVec = emitter->_raw[name]; + VEC_TYPE tmpVec = eventEmitter->_raw[name]; - emitter->_listeners[name].clear(); - emitter->_raw[name].clear(); + eventEmitter->_listeners[name].clear(); + eventEmitter->_raw[name].clear(); for (IT_TYPE it = tmpVec.begin(); it != tmpVec.end(); ++it) { v8::Local args[] = { JS_STR(name.c_str()), Nan::New(*it) }; - emitter->emit("removeListener", 2, args); + eventEmitter->emit("removeListener", 2, args); } } - static NAN_METHOD(jsRemoveListener) { THIS_EMITTER; + static NAN_METHOD(jsRemoveListener) { THIS_EVENT_EMITTER; REQ_UTF8_ARG(0, n); REQ_FUN_ARG(1, raw); @@ -446,7 +509,7 @@ protected: std::string name = std::string(*n); - VEC_TYPE &rawList = emitter->_raw[name]; + VEC_TYPE &rawList = eventEmitter->_raw[name]; if (rawList.empty()) { return; @@ -459,7 +522,7 @@ protected: if (*it == persistentRaw) { rawList.erase(it); if (rawList.empty()) { - emitter->_raw.erase(name); + eventEmitter->_raw.erase(name); } break; } @@ -467,48 +530,48 @@ protected: } - VEC_TYPE &wrapList = emitter->_listeners[name]; + VEC_TYPE &wrapList = eventEmitter->_listeners[name]; - if (emitter->_wrappedIds.size() == 0) { + if (eventEmitter->_wrappedIds.size() == 0) { for (IT_TYPE it = wrapList.begin(); it != wrapList.end(); ++it) { if (*it == persistentRaw) { wrapList.erase(it); if (wrapList.empty()) { - emitter->_listeners.erase(name); + eventEmitter->_listeners.erase(name); } break; } } - emitter->emit("removeListener", 2, args); + eventEmitter->emit("removeListener", 2, args); return; } - for (FNMAP_IT_TYPE itRaw = emitter->_rawIds.begin(); itRaw != emitter->_rawIds.end(); ++itRaw) { + for (FNMAP_IT_TYPE itRaw = eventEmitter->_rawIds.begin(); itRaw != eventEmitter->_rawIds.end(); ++itRaw) { if (persistentRaw == itRaw->second) { - FN_TYPE fn = emitter->_wrappedIds[itRaw->first]; + FN_TYPE fn = eventEmitter->_wrappedIds[itRaw->first]; for (IT_TYPE it = wrapList.begin(); it != wrapList.end(); ++it) { if (*it == fn) { wrapList.erase(it); if (wrapList.empty()) { - emitter->_listeners.erase(name); + eventEmitter->_listeners.erase(name); } break; } } - emitter->_wrappedIds.erase(itRaw->first); - emitter->_rawIds.erase(itRaw->first); + eventEmitter->_wrappedIds.erase(itRaw->first); + eventEmitter->_rawIds.erase(itRaw->first); break; @@ -516,25 +579,25 @@ protected: } - emitter->emit("removeListener", 2, args); + eventEmitter->emit("removeListener", 2, args); } - static NAN_METHOD(jsSetMaxListeners) { THIS_EMITTER; + static NAN_METHOD(jsSetMaxListeners) { THIS_EVENT_EMITTER; REQ_INT32_ARG(0, value); - emitter->_maxListeners = value; + eventEmitter->_maxListeners = value; } - static NAN_METHOD(jsRawListeners) { THIS_EMITTER; + static NAN_METHOD(jsRawListeners) { THIS_EVENT_EMITTER; REQ_UTF8_ARG(0, name); - VEC_TYPE &list = emitter->_raw[*name]; + VEC_TYPE &list = eventEmitter->_raw[*name]; v8::Local jsListeners = Nan::New(list.size()); @@ -557,6 +620,8 @@ protected: private: + bool _isDestroyed; + int _maxListeners; MAP_TYPE _listeners; diff --git a/package.json b/package.json index 410de24..5a3f88d 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "addon-tools-raub", "author": "Luis Blanco ", "description": "A set of extra tools for Node.js addons", - "version": "0.1.1", + "version": "0.1.2", "main": "index.js", "keywords": [ "node",