Skip to content

Instantly share code, notes, and snippets.

@lynxerzhang
Last active October 8, 2015 06:28
Show Gist options
  • Save lynxerzhang/3291503 to your computer and use it in GitHub Desktop.
Save lynxerzhang/3291503 to your computer and use it in GitHub Desktop.
modify RichardLord's Signal version @see https://github.com/richardlord/Signals
package
{
import flash.utils.Dictionary;
/**
* modified RichardLord's Signal version
* @see https://github.com/richardlord/Signals
*/
public class Signals{
private var nodeDict:Dictionary;
private var head:ListenerNode;
private var tail:ListenerNode;
private var cacheHead:ListenerNode;
private var cacheTail:ListenerNode;
private var nodePool:ListenerNodePool;
/**
* construct Signal
*/
public function Signals():void{
nodePool = new ListenerNodePool();
nodeDict = new Dictionary(false);
}
/**
* dispatch to all observer
*/
public function dispatch(...args):void{
dispatching = true;
if(head){
for(var node:ListenerNode = head; node; node = node.next){
var fun:Function = node.listener;
if(node.executeOnce){
remove(fun);
}
fun.apply(null, args);
}
}
dispatching = false;
//the remove operation complete
nodePool.release();
//the add operation complete
if(cacheHead){
if(!head){
head = cacheHead;
tail = cacheTail;
}
else{
tail.next = cacheHead;
cacheHead.prev = tail;
tail = cacheTail;
}
}
cacheHead = null;
cacheTail = null;
}
/*create a execute function*/
public function add(fun:Function, executeOnce:Boolean = false):void{
if(nodeDict[fun]){
return;
}
var node:ListenerNode = nodePool.get();
node.listener = fun;
node.executeOnce = executeOnce;
nodeDict[fun] = node;
addNode(node);
}
/*remove all node*/
public function removeAll():void{
nodePool.remove();
for(var fun:* in nodeDict){
delete nodeDict[fun];
}
//nodeDict = new Dictionary(false);
head = null;
tail = null;
cacheHead = null;
cacheTail = null;
}
/*remove specfied fun*/
public function remove(fun:Function):void{
var node:ListenerNode = nodeDict[fun];
if(!node){
return;
}
if(node == head){
head = head.next;
}
if(node == tail){
tail = tail.next;
}
if(node == cacheHead){
cacheHead = cacheHead.next;
}
if(node == cacheTail){
cacheTail = cacheTail.next;
}
if(node.next){
node.next.prev = node.prev;
}
if(node.prev){
node.prev.next = node.next;
}
delete nodeDict[fun];
if(dispatching){
nodePool.cache(node);
}
else{
nodePool.dispose(node);
}
}
private var dispatching:Boolean = false;
private function addNode(node:ListenerNode):void{
if(dispatching){
if(!cacheHead){
cacheHead = cacheTail = node;
}
else{
node.prev = cacheTail;
cacheTail.next = node;
cacheTail = node;
}
}
else{
if(!head){
tail = head = node;
}
else{
node.prev = tail;
tail.next = node;
tail = node;
}
}
}
}
}
/*node pool*/
internal class ListenerNodePool
{
/*tail*/
private var tail:ListenerNode;
/*cache tail*/
private var cacheTail:ListenerNode;
/*get the idle node*/
public function get():ListenerNode{
if(tail){
var node:ListenerNode = tail;
tail = tail.prev;
return node;
}
else{
return new ListenerNode();
}
}
/*dispose specfied node*/
public function dispose(node:ListenerNode):void{
node.prev = tail;
node.next = null;
node.listener = null;
node.executeOnce = false;
tail = node;
}
/*cache specfied node and free in the dispatching end state*/
public function cache(node:ListenerNode):void{
//node.listener = null;
//node.next = null;
node.executeOnce = false;
node.prev = cacheTail;
cacheTail = node;
}
/*release all cache node and add to tail node for save performance*/
public function release():void{
while(cacheTail != null){
var node:ListenerNode = cacheTail;
node.next = null;
node.listener = null;
cacheTail = cacheTail.prev;
node.prev = tail;
tail = node;
}
}
/*gc the cache list*/
public function remove():void{
release();
cacheTail = null;
tail = null;
}
}
/*node*/
internal class ListenerNode
{
/*next data point*/
public var next:ListenerNode;
/*prev data point*/
public var prev:ListenerNode;
/*listener reference*/
public var listener:Function;
/*whether run once and auto remove from signal*/
public var executeOnce:Boolean;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment