CallbackList.pm
上传用户:market2
上传日期:2018-11-18
资源大小:18786k
文件大小:7k
源码类别:

外挂编程

开发平台:

Windows_Unix

  1. #########################################################################
  2. #  OpenKore - Generic utility functions
  3. #
  4. #  Copyright (c) 2006 OpenKore Development Team
  5. #
  6. #  This software is open source, licensed under the GNU General Public
  7. #  License, version 2.
  8. #  Basically, this means that you're allowed to modify and distribute
  9. #  this software. However, if you distribute modified versions, you MUST
  10. #  also distribute the source code.
  11. #  See http://www.gnu.org/licenses/gpl.html for the full license.
  12. #########################################################################
  13. ##
  14. # MODULE DESCRIPTION: Callback functions holder
  15. #
  16. # <h3>What is an event?</h3>
  17. # An event in is a way for a class to provide notifications to clients of
  18. # that class when some interesting thing happens to an object. The most
  19. # familiar use for events is in graphical user interfaces; typically, the
  20. # classes that represent controls in the interface have events that are
  21. # notified when the user does something to the control (for example, click
  22. # a button).
  23. #
  24. # An event is the outcome of an action. There are two important
  25. # terms with respect to events. The <i>event source</i> and the <i>event
  26. # receiver</i>. The object that raises the event is called event source and
  27. # the object or callback function that responds to the event is called event receiver.
  28. # The communication channel between an event source and an event receiver is
  29. # this class, CallbackList.<br>
  30. # <small>(Explanation taken from
  31. # <a href="http://www.c-sharpcorner.com/UploadFile/sksaha/EventsinNet11152005043514AM/EventsinNet.aspx">CSharpCorner</a>
  32. # and slightly modified.</small>
  33. #
  34. # A CallbackList is used to implement OpenKore's event model.
  35. #
  36. # <h3>Example 1: How it works</h3>
  37. # Here's a simple example, which demonstrates how CallbackList actually works.
  38. # <pre class="example">
  39. # my $cl = new CallbackList("my l33t event name");
  40. # $cl->add(undef, &myCallback);
  41. # $cl->call();  # myCallback() will now be called.
  42. #
  43. # sub myCallback {
  44. #     print "I have been called!n";
  45. # }
  46. # </pre>
  47. #
  48. # <h3>Example 2: Simple usage - adding functions as callbacks</h3>
  49. # The @MODULE(ActorList) class is a well-known class which supports events.
  50. # Whenever you add an Actor to an ActorList, an <b>onAdd</b> event is triggered.
  51. # This example shows you how to respond to an onAdd event.
  52. #
  53. # This also demonstrates how $CallbackList->add() and $CallbackList->remove()
  54. # work.
  55. # <pre class="example">
  56. # my $monstersList = new ActorList("Actor::Monster");
  57. # my $callbackID = $monstersList->onAdd->add(undef, &monsterAdded);
  58. #
  59. # # monsterAdded() will now be called.
  60. # $monstersList->add(new Actor::Monster());
  61. #
  62. # # Unregister the previously registred callback.
  63. # $monstersList->onAdd->remove($callbackID);
  64. # # monsterAdded() will NOT be called.
  65. # $monstersList->add(new Actor::Monster());
  66. #
  67. # sub monsterAdded {
  68. #     print "A monster has been added to the monsters list!n";
  69. # }
  70. # </pre>
  71. package CallbackList;
  72. use strict;
  73. use Carp::Assert;
  74. use Scalar::Util;
  75. # Field identifiers for items inside $CallbackList->[CALLBACKS]
  76. use constant {
  77. FUNCTION => 0,
  78. ID       => 1,
  79. OBJECT   => 2,
  80. USERDATA => 3
  81. };
  82. ### CATEGORY: Class CallbackList
  83. # class CallbackList is_a Array<CallbackItem>
  84. #
  85. # Invariant:
  86. #     for all i in [0 .. size - 1]:
  87. #         defined(self[i])
  88. #         ${self[i][ID]} == i
  89. # struct CallbackItem is_a Array {
  90. #     Function FUNCTION:
  91. #         Reference to a function.
  92. #         Invariant: defined(FUNCTION)
  93. #
  94. #     int* ID:
  95. #         A reference to the index of this item.
  96. #         Invariant: defined(ID)
  97. #
  98. #     Object OBJECT:
  99. #         The callback's class object. May not exist (if no object was passed to
  100. #         add()) or be undef (if the object was destroyed).
  101. #
  102. #     Scalar USERDATA:
  103. #         May be undef.
  104. # }
  105. ##
  106. # CallbackList CallbackList->new()
  107. # Ensures:
  108. #     $self->size() == 0
  109. #
  110. # Create a new CallbackList object.
  111. sub new {
  112. my ($class) = @_;
  113. return bless [], $class;
  114. }
  115. ##
  116. # Scalar $CallbackList->add(Object object, function, userData)
  117. # object:   An object to pass to the callback function, as the first argument. May be undef.
  118. # function: A callback function.
  119. # userData: A user data argument to pass to the callback function when it's called. May be undef.
  120. # Returns:  An ID, which can be used by remove() to remove this callback from the list.
  121. # Requires: defined($function)
  122. # Ensures:  defined(result)
  123. #
  124. # Add a new callback function to this CallbackList. See $CallbackList->call()
  125. # for information about how $function will be called.
  126. #
  127. # CallbackList will internally hold a weak reference to $object,
  128. # so there will be no garbage collection problems if this $CallbackList is
  129. # a member of $object.
  130. sub add {
  131. my ($self, $object, $function, $userData) = @_;
  132. assert(defined $function) if DEBUG;
  133. assert(!defined($object) || Scalar::Util::blessed($object)) if DEBUG;
  134. my @item;
  135. $item[FUNCTION] = $function;
  136. if (defined $object) {
  137. $item[OBJECT] = $object;
  138. Scalar::Util::weaken($item[OBJECT]);
  139. }
  140. if (defined $userData) {
  141. $item[USERDATA] = $userData;
  142. }
  143. push @{$self}, @item;
  144. my $index = @{$self} - 1;
  145. my $ID = $index;
  146. $item[ID] = $ID;
  147. return $ID;
  148. }
  149. ##
  150. # void $CallbackList->remove(ID)
  151. # ID: An ID, as returned by $CallbackList->add()
  152. # Requires: defined($ID)
  153. #
  154. # Removes a callback from this CallbackList.
  155. sub remove {
  156. my ($self, $ID) = @_;
  157. assert(defined $ID) if DEBUG;
  158. return if (!defined($$ID) || $$ID < 0 || $$ID >= @{$self});
  159. my $callbacks = $self;
  160. for (my $i = $$ID + 1; $i < @{$callbacks}; $i++) {
  161. ${$callbacks->[$i][ID]}--;
  162. }
  163. splice(@{$callbacks}, $$ID, 1);
  164. $$ID = undef;
  165. }
  166. ##
  167. # void $CallbackList->call(Scalar source, [argument])
  168. # source: The object which emitted this event.
  169. #
  170. # Call all callback functions in this CallbackList. Each function
  171. # $function will be called as follows:
  172. # <pre>
  173. # $function->($object, $source, $argument, $userData);
  174. # </pre>
  175. # `l
  176. # - $object and $userData are the arguments passed to $CallbackList->add()
  177. # - $list is this CallbackList.
  178. # - $source and $argument are the parameters passed to this method.
  179. # `l`
  180. sub call {
  181. my $IDsToRemove;
  182. foreach my $item (@{$_[0]}) {
  183. if (exists $item->[OBJECT] && !defined $item->[OBJECT]) {
  184. # This object was destroyed, so remove the corresponding callback.
  185. $IDsToRemove ||= []; # We use a reference to an array as micro-optimization.
  186. push @{$IDsToRemove}, $item->[ID];
  187. } else {
  188. $item->[FUNCTION]->($item->[OBJECT], $_[1], $_[2], $item->[USERDATA]);
  189. }
  190. }
  191. if ($IDsToRemove) {
  192. foreach my $ID (@{$IDsToRemove}) {
  193. $_[0]->remove($ID);
  194. }
  195. }
  196. }
  197. ##
  198. # int $CallbackList->size()
  199. # Ensures: result >= 0
  200. #
  201. # Returns the number of registered callbacks in this list.
  202. sub size {
  203. return @{$_[0]};
  204. }
  205. ##
  206. # boolean $CallbackList->empty()
  207. #
  208. # Check whether there are any callbacks in this CallbackList.
  209. sub empty {
  210. return @{$_[0]} == 0;
  211. }
  212. ##
  213. # CallbackList $CallbackList->deepCopy()
  214. # Ensures: defined(result)
  215. #
  216. # Create a deep copy of this CallbackList.
  217. sub deepCopy {
  218. my ($self) = @_;
  219. my $copy = new CallbackList();
  220. foreach my $item (@{$self}) {
  221. my @callbackItemCopy = @{$item};
  222. push @{$copy}, @callbackItemCopy;
  223. }
  224. return $copy;
  225. }
  226. ##
  227. # void $CallbackList->checkValidity()
  228. #
  229. # Check whether all internal invariants are true.
  230. sub checkValidity {
  231. my ($self) = @_;
  232. for (my $i = 0; $i < @{$self}; $i++) {
  233. my $k = $self->[$i];
  234. assert defined($k);
  235. assert defined($k->[FUNCTION]);
  236. assert defined($k->[ID]);
  237. assert ${$k->[ID]} == $i;
  238. }
  239. }
  240. 1;