From edae9f26e4f25a6a49b3bc6fb955f3bb105804c8 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 13 Nov 2024 22:23:43 +0000 Subject: [PATCH] Reduce number of classes --- src/event/AsyncHandlerList.php | 43 ------- src/event/AsyncHandlerListManager.php | 22 +++- src/event/BaseHandlerList.php | 170 -------------------------- src/event/BaseHandlerListManager.php | 10 +- src/event/HandlerList.php | 142 ++++++++++++++++++++- src/event/HandlerListManager.php | 2 +- 6 files changed, 164 insertions(+), 225 deletions(-) delete mode 100644 src/event/AsyncHandlerList.php delete mode 100644 src/event/BaseHandlerList.php diff --git a/src/event/AsyncHandlerList.php b/src/event/AsyncHandlerList.php deleted file mode 100644 index db5c612ff..000000000 --- a/src/event/AsyncHandlerList.php +++ /dev/null @@ -1,43 +0,0 @@ - - */ -class AsyncHandlerList extends BaseHandlerList{ - protected function sortSamePriorityListeners(array $listeners) : array{ - uasort($listeners, function(AsyncRegisteredListener $left, AsyncRegisteredListener $right) : int{ - //While the system can handle these in any order, it's better for latency if concurrent handlers - //are processed together. It doesn't matter whether they are processed before or after exclusive handlers. - if($right->canBeCalledConcurrently()){ - return $left->canBeCalledConcurrently() ? 0 : 1; - } - return -1; - }); - return $listeners; - } -} diff --git a/src/event/AsyncHandlerListManager.php b/src/event/AsyncHandlerListManager.php index 8dd9461c9..b6d249919 100644 --- a/src/event/AsyncHandlerListManager.php +++ b/src/event/AsyncHandlerListManager.php @@ -23,6 +23,8 @@ declare(strict_types=1); namespace pocketmine\event; +use function uasort; + /** * @phpstan-extends BaseHandlerListManager */ @@ -37,7 +39,23 @@ final class AsyncHandlerListManager extends BaseHandlerListManager{ return AsyncEvent::class; } - protected function createHandlerList(string $event, ?BaseHandlerList $parentList, RegisteredListenerCache $handlerCache) : BaseHandlerList{ - return new AsyncHandlerList($event, $parentList, $handlerCache); + /** + * @phpstan-param array $listeners + * @phpstan-return array + */ + private static function sortSamePriorityHandlers(array $listeners) : array{ + uasort($listeners, function(AsyncRegisteredListener $left, AsyncRegisteredListener $right) : int{ + //While the system can handle these in any order, it's better for latency if concurrent handlers + //are processed together. It doesn't matter whether they are processed before or after exclusive handlers. + if($right->canBeCalledConcurrently()){ + return $left->canBeCalledConcurrently() ? 0 : 1; + } + return -1; + }); + return $listeners; + } + + protected function createHandlerList(string $event, ?HandlerList $parentList, RegisteredListenerCache $handlerCache) : HandlerList{ + return new HandlerList($event, $parentList, $handlerCache, self::sortSamePriorityHandlers(...)); } } diff --git a/src/event/BaseHandlerList.php b/src/event/BaseHandlerList.php deleted file mode 100644 index ebdd7c890..000000000 --- a/src/event/BaseHandlerList.php +++ /dev/null @@ -1,170 +0,0 @@ -> - */ - private array $handlerSlots = []; - - /** - * @var RegisteredListenerCache[] - * @phpstan-var array> - */ - private array $affectedHandlerCaches = []; - - /** - * @phpstan-param class-string $class - * @phpstan-param ?static $parentList - * @phpstan-param RegisteredListenerCache $handlerCache - */ - public function __construct( - private string $class, - private ?BaseHandlerList $parentList, - private RegisteredListenerCache $handlerCache = new RegisteredListenerCache() - ){ - for($list = $this; $list !== null; $list = $list->parentList){ - $list->affectedHandlerCaches[spl_object_id($this->handlerCache)] = $this->handlerCache; - } - } - - /** - * @phpstan-param TListener $listener - */ - public function register(BaseRegisteredListener $listener) : void{ - if(isset($this->handlerSlots[$listener->getPriority()][spl_object_id($listener)])){ - throw new \InvalidArgumentException("This listener is already registered to priority {$listener->getPriority()} of event {$this->class}"); - } - $this->handlerSlots[$listener->getPriority()][spl_object_id($listener)] = $listener; - $this->invalidateAffectedCaches(); - } - - /** - * @param BaseRegisteredListener[] $listeners - * @phpstan-param array $listeners - */ - public function registerAll(array $listeners) : void{ - foreach($listeners as $listener){ - $this->register($listener); - } - $this->invalidateAffectedCaches(); - } - - /** - * @phpstan-param TListener|Plugin|Listener $object - */ - public function unregister(BaseRegisteredListener|Plugin|Listener $object) : void{ - if($object instanceof Plugin || $object instanceof Listener){ - foreach($this->handlerSlots as $priority => $list){ - foreach($list as $hash => $listener){ - if(($object instanceof Plugin && $listener->getPlugin() === $object) - || ($object instanceof Listener && (new \ReflectionFunction($listener->getHandler()))->getClosureThis() === $object) //this doesn't even need to be a listener :D - ){ - unset($this->handlerSlots[$priority][$hash]); - } - } - } - }else{ - unset($this->handlerSlots[$object->getPriority()][spl_object_id($object)]); - } - $this->invalidateAffectedCaches(); - } - - public function clear() : void{ - $this->handlerSlots = []; - $this->invalidateAffectedCaches(); - } - - /** - * @return BaseRegisteredListener[] - * @phpstan-return array - */ - public function getListenersByPriority(int $priority) : array{ - return $this->handlerSlots[$priority] ?? []; - } - - /** - * @phpstan-return static - */ - public function getParent() : ?BaseHandlerList{ - return $this->parentList; - } - - /** - * Invalidates all known caches which might be affected by this list's contents. - */ - private function invalidateAffectedCaches() : void{ - foreach($this->affectedHandlerCaches as $cache){ - $cache->list = null; - } - } - - /** - * @param BaseRegisteredListener[] $listeners - * @phpstan-param array $listeners - * - * @return BaseRegisteredListener[] - * @phpstan-return array - */ - abstract protected function sortSamePriorityListeners(array $listeners) : array; - - /** - * @return BaseRegisteredListener[] - * @phpstan-return list - */ - public function getListenerList() : array{ - if($this->handlerCache->list !== null){ - return $this->handlerCache->list; - } - - $handlerLists = []; - for($currentList = $this; $currentList !== null; $currentList = $currentList->parentList){ - $handlerLists[] = $currentList; - } - - $listenersByPriority = []; - foreach($handlerLists as $currentList){ - foreach($currentList->handlerSlots as $priority => $listeners){ - $listenersByPriority[$priority] = array_merge($listenersByPriority[$priority] ?? [], $this->sortSamePriorityListeners($listeners)); - } - } - - //TODO: why on earth do the priorities have higher values for lower priority? - krsort($listenersByPriority, SORT_NUMERIC); - - return $this->handlerCache->list = array_merge(...$listenersByPriority); - } -} diff --git a/src/event/BaseHandlerListManager.php b/src/event/BaseHandlerListManager.php index c8f0a59e7..5183fed9b 100644 --- a/src/event/BaseHandlerListManager.php +++ b/src/event/BaseHandlerListManager.php @@ -30,11 +30,11 @@ use pocketmine\utils\Utils; * @phpstan-template TEvent of Event|AsyncEvent * @phpstan-template TRegisteredListener of BaseRegisteredListener * - * @phpstan-type THandlerList BaseHandlerList + * @phpstan-type THandlerList HandlerList */ abstract class BaseHandlerListManager{ /** - * @var BaseHandlerList[] classname => BaseHandlerList + * @var HandlerList[] classname => HandlerList * @phpstan-var array, THandlerList> */ private array $allLists = []; @@ -92,12 +92,12 @@ abstract class BaseHandlerListManager{ /** * @phpstan-param class-string $event - * @phpstan-param THandlerList|null $parentList + * @phpstan-param HandlerList|null $parentList * @phpstan-param RegisteredListenerCache $handlerCache * * @phpstan-return THandlerList */ - abstract protected function createHandlerList(string $event, ?BaseHandlerList $parentList, RegisteredListenerCache $handlerCache) : BaseHandlerList; + abstract protected function createHandlerList(string $event, ?HandlerList $parentList, RegisteredListenerCache $handlerCache) : HandlerList; /** * Returns the HandlerList for listeners that explicitly handle this event. @@ -110,7 +110,7 @@ abstract class BaseHandlerListManager{ * @throws \ReflectionException * @throws \InvalidArgumentException */ - public function getListFor(string $event) : BaseHandlerList{ + public function getListFor(string $event) : HandlerList{ if(isset($this->allLists[$event])){ return $this->allLists[$event]; } diff --git a/src/event/HandlerList.php b/src/event/HandlerList.php index 53c5148fa..b1d53ab86 100644 --- a/src/event/HandlerList.php +++ b/src/event/HandlerList.php @@ -23,11 +23,145 @@ declare(strict_types=1); namespace pocketmine\event; +use pocketmine\plugin\Plugin; +use function array_merge; +use function krsort; +use function spl_object_id; +use const SORT_NUMERIC; + /** - * @phpstan-extends BaseHandlerList + * @phpstan-template TListener of BaseRegisteredListener */ -class HandlerList extends BaseHandlerList{ - protected function sortSamePriorityListeners(array $listeners) : array{ - return $listeners; +class HandlerList{ + /** + * @var BaseRegisteredListener[][] + * @phpstan-var array> + */ + private array $handlerSlots = []; + + /** + * @var RegisteredListenerCache[] + * @phpstan-var array> + */ + private array $affectedHandlerCaches = []; + + /** + * @phpstan-param class-string $class + * @phpstan-param ?static $parentList + * @phpstan-param RegisteredListenerCache $handlerCache + * @phpstan-param ?\Closure(array) : array $sortSamePriorityHandlers + */ + public function __construct( + private string $class, + private ?HandlerList $parentList, + private RegisteredListenerCache $handlerCache = new RegisteredListenerCache(), + private ?\Closure $sortSamePriorityHandlers = null + ){ + for($list = $this; $list !== null; $list = $list->parentList){ + $list->affectedHandlerCaches[spl_object_id($this->handlerCache)] = $this->handlerCache; + } + } + + /** + * @phpstan-param TListener $listener + */ + public function register(BaseRegisteredListener $listener) : void{ + if(isset($this->handlerSlots[$listener->getPriority()][spl_object_id($listener)])){ + throw new \InvalidArgumentException("This listener is already registered to priority {$listener->getPriority()} of event {$this->class}"); + } + $this->handlerSlots[$listener->getPriority()][spl_object_id($listener)] = $listener; + $this->invalidateAffectedCaches(); + } + + /** + * @param BaseRegisteredListener[] $listeners + * @phpstan-param array $listeners + */ + public function registerAll(array $listeners) : void{ + foreach($listeners as $listener){ + $this->register($listener); + } + $this->invalidateAffectedCaches(); + } + + /** + * @phpstan-param TListener|Plugin|Listener $object + */ + public function unregister(BaseRegisteredListener|Plugin|Listener $object) : void{ + if($object instanceof Plugin || $object instanceof Listener){ + foreach($this->handlerSlots as $priority => $list){ + foreach($list as $hash => $listener){ + if(($object instanceof Plugin && $listener->getPlugin() === $object) + || ($object instanceof Listener && (new \ReflectionFunction($listener->getHandler()))->getClosureThis() === $object) //this doesn't even need to be a listener :D + ){ + unset($this->handlerSlots[$priority][$hash]); + } + } + } + }else{ + unset($this->handlerSlots[$object->getPriority()][spl_object_id($object)]); + } + $this->invalidateAffectedCaches(); + } + + public function clear() : void{ + $this->handlerSlots = []; + $this->invalidateAffectedCaches(); + } + + /** + * @return BaseRegisteredListener[] + * @phpstan-return array + */ + public function getListenersByPriority(int $priority) : array{ + return $this->handlerSlots[$priority] ?? []; + } + + /** + * @phpstan-return static + */ + public function getParent() : ?HandlerList{ + return $this->parentList; + } + + /** + * Invalidates all known caches which might be affected by this list's contents. + */ + private function invalidateAffectedCaches() : void{ + foreach($this->affectedHandlerCaches as $cache){ + $cache->list = null; + } + } + + /** + * @return BaseRegisteredListener[] + * @phpstan-return list + */ + public function getListenerList() : array{ + if($this->handlerCache->list !== null){ + return $this->handlerCache->list; + } + + $handlerLists = []; + for($currentList = $this; $currentList !== null; $currentList = $currentList->parentList){ + $handlerLists[] = $currentList; + } + + $listenersByPriority = []; + foreach($handlerLists as $currentList){ + foreach($currentList->handlerSlots as $priority => $listeners){ + $listenersByPriority[$priority] = array_merge( + $listenersByPriority[$priority] ?? [], + $this->sortSamePriorityHandlers !== null ? + ($this->sortSamePriorityHandlers)($listeners) : + $listeners + ); + } + } + + //TODO: why on earth do the priorities have higher values for lower priority? + krsort($listenersByPriority, SORT_NUMERIC); + + return $this->handlerCache->list = array_merge(...$listenersByPriority); } } diff --git a/src/event/HandlerListManager.php b/src/event/HandlerListManager.php index 85be52387..489a3af90 100644 --- a/src/event/HandlerListManager.php +++ b/src/event/HandlerListManager.php @@ -37,7 +37,7 @@ class HandlerListManager extends BaseHandlerListManager{ return Event::class; } - protected function createHandlerList(string $event, ?BaseHandlerList $parentList, RegisteredListenerCache $handlerCache) : BaseHandlerList{ + protected function createHandlerList(string $event, ?HandlerList $parentList, RegisteredListenerCache $handlerCache) : HandlerList{ return new HandlerList($event, $parentList, $handlerCache); } }