124 lines
4.5 KiB
Python
124 lines
4.5 KiB
Python
# eventpy library
|
|
# Copyright (C) 2020 Wang Qi (wqking)
|
|
# Github: https://github.com/wqking/eventpy
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
import eventpy.policy
|
|
import eventpy.internal.linkedlist as linkedlist
|
|
import eventpy.internal.lockguard as lockguard
|
|
|
|
import inspect
|
|
|
|
class CallbackList :
|
|
class NodeData :
|
|
def __init__(self, callback, counter) :
|
|
self._callback = callback
|
|
self._counter = counter
|
|
|
|
def __init__(self, policy = eventpy.policy.defaultPolicy) :
|
|
self._policy = policy.clone()
|
|
self._lock = self._policy.lockClass()
|
|
self._list = linkedlist.LinkedList(self._lock)
|
|
self._currentCounter = 0
|
|
|
|
def empty(self) :
|
|
return self._list.empty()
|
|
|
|
def append(self, callback) :
|
|
node = linkedlist.LinkedListNode(CallbackList.NodeData(callback, self._getNextCounter()))
|
|
self._list.append(node)
|
|
return node
|
|
|
|
def prepend(self, callback) :
|
|
node = linkedlist.LinkedListNode(CallbackList.NodeData(callback, self._getNextCounter()))
|
|
self._list.prepend(node)
|
|
return node
|
|
|
|
def insert(self, callback, before) :
|
|
node = linkedlist.LinkedListNode(CallbackList.NodeData(callback, self._getNextCounter()))
|
|
self._list.insert(node, before)
|
|
return node
|
|
|
|
def remove(self, node) :
|
|
if node is not None :
|
|
def postProcess(n) :
|
|
n.getData()._counter = 0
|
|
self._list.remove(node, postProcess)
|
|
|
|
def forEach(self, func) :
|
|
with lockguard.LockGuard(self._lock) :
|
|
node = self._list.getHead()
|
|
counter = self._currentCounter
|
|
invoke = _selectForEachInvoke(func)
|
|
while node is not None :
|
|
nodeCounter = node.getData()._counter
|
|
if nodeCounter != 0 and counter >= nodeCounter :
|
|
invoke(node)
|
|
with lockguard.LockGuard(self._lock) :
|
|
node = node._next
|
|
|
|
def forEachIf(self, func) :
|
|
with lockguard.LockGuard(self._lock) :
|
|
node = self._list.getHead()
|
|
counter = self._currentCounter
|
|
invoke = _selectForEachInvoke(func)
|
|
while node is not None :
|
|
nodeCounter = node.getData()._counter
|
|
if nodeCounter != 0 and counter >= nodeCounter :
|
|
if not invoke(node) :
|
|
return False
|
|
with lockguard.LockGuard(self._lock) :
|
|
node = node._next
|
|
return True
|
|
|
|
def __call__(self, *args, **kwargs) :
|
|
with lockguard.LockGuard(self._lock) :
|
|
node = self._list.getHead()
|
|
counter = self._currentCounter
|
|
while node is not None :
|
|
nodeCounter = node.getData()._counter
|
|
if nodeCounter != 0 and counter >= nodeCounter :
|
|
node.getData()._callback(*args, **kwargs)
|
|
if not self._policy.canContinueInvoking(*args, **kwargs) :
|
|
break
|
|
with lockguard.LockGuard(self._lock) :
|
|
node = node._next
|
|
|
|
def _getNextCounter(self) :
|
|
self._currentCounter += 1
|
|
result = self._currentCounter
|
|
if result <= 0 : # overflow, let's reset all nodes' counters.
|
|
with lockguard.LockGuard(self._lock) :
|
|
node = self._list.getHead()
|
|
while node is not None :
|
|
node.getData()._counter = 1
|
|
node = node.getNext()
|
|
if self._currentCounter < 0 :
|
|
self._currentCounter = 0
|
|
self._currentCounter += 1
|
|
result = self._currentCounter
|
|
|
|
return result
|
|
|
|
def _selectForEachInvoke(func) :
|
|
def _forEachInvoke1(node, func = func) :
|
|
return func(node.getData()._callback)
|
|
|
|
def _forEachInvoke2(node, func = func) :
|
|
return func(node, node.getData()._callback)
|
|
|
|
sig = inspect.signature(func)
|
|
if len(sig.parameters) >= 2 :
|
|
return _forEachInvoke2
|
|
else :
|
|
return _forEachInvoke1
|
|
|