2 // System.MultiCastDelegate.cs
5 // Miguel de Icaza (miguel@ximian.com)
6 // Daniel Stodden (stodden@in.tum.de)
8 // (C) Ximian, Inc. http://www.ximian.com
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System
.Collections
;
35 using System
.Runtime
.Serialization
;
39 public abstract class MulticastDelegate
: Delegate
41 private MulticastDelegate prev
;
42 private MulticastDelegate kpm_next
;
44 protected MulticastDelegate (object target
, string method
)
45 : base (target
, method
)
50 protected MulticastDelegate (Type target_type
, string method
)
51 : base (target_type
, method
)
56 public override void GetObjectData (SerializationInfo info
, StreamingContext context
)
58 base.GetObjectData (info
, context
);
62 protected override object DynamicInvokeImpl (object[] args
)
65 prev
.DynamicInvokeImpl (args
);
67 return base.DynamicInvokeImpl (args
);
71 // Equals: two multicast delegates are equal if their base is equal
72 // and their invocations list is equal.
74 public override bool Equals (object o
)
79 MulticastDelegate d
= (MulticastDelegate
) o
;
81 if (this.prev
== null) {
88 return this.prev
.Equals (d
.prev
);
92 // FIXME: This could use some improvements.
94 public override int GetHashCode ()
96 return base.GetHashCode ();
100 // Return, in order of invocation, the invocation list
101 // of a MulticastDelegate
103 public override Delegate
[] GetInvocationList ()
106 for (d
= (MulticastDelegate
) this.Clone (); d
.prev
!= null; d
= d
.prev
)
109 if (d
.kpm_next
== null) {
110 MulticastDelegate other
= (MulticastDelegate
) d
.Clone ();
112 other
.kpm_next
= null;
113 return new Delegate
[1] { other }
;
116 ArrayList list
= new ArrayList ();
117 for (; d
!= null; d
= d
.kpm_next
) {
118 MulticastDelegate other
= (MulticastDelegate
) d
.Clone ();
120 other
.kpm_next
= null;
124 return (Delegate
[]) list
.ToArray (typeof (Delegate
));
128 // Combines this MulticastDelegate with the (Multicast)Delegate `follow'.
129 // This does _not_ combine with Delegates. ECMA states the whole delegate
130 // thing should have better been a simple System.Delegate class.
131 // Compiler generated delegates are always MulticastDelegates.
133 protected override Delegate
CombineImpl (Delegate follow
)
135 MulticastDelegate combined
, orig
, clone
;
137 if (this.GetType() != follow
.GetType ())
138 throw new ArgumentException (Locale
.GetText ("Incompatible Delegate Types."));
140 combined
= (MulticastDelegate
)follow
.Clone ();
142 for (clone
= combined
, orig
= ((MulticastDelegate
)follow
).prev
; orig
!= null; orig
= orig
.prev
) {
144 clone
.prev
= (MulticastDelegate
)orig
.Clone ();
148 clone
.prev
= (MulticastDelegate
)this.Clone ();
150 for (clone
= clone
.prev
, orig
= this.prev
; orig
!= null; orig
= orig
.prev
) {
152 clone
.prev
= (MulticastDelegate
)orig
.Clone ();
159 private bool BaseEquals (MulticastDelegate
value)
161 return base.Equals (value);
165 * Perform a slightly crippled version of
166 * Knuth-Pratt-Morris over MulticastDelegate chains.
167 * Border values are set as pointers in kpm_next;
168 * Generally, KPM border arrays are length n+1 for
169 * strings of n. This one works with length n at the
170 * expense of a few additional comparisions.
172 private static MulticastDelegate
KPM (MulticastDelegate needle
, MulticastDelegate haystack
,
173 out MulticastDelegate tail
)
175 MulticastDelegate nx
, hx
;
179 nx
= needle
.kpm_next
= null;
181 while ((nx
!= null) && (!nx
.BaseEquals (hx
)))
188 nx
= nx
== null ? needle
: nx
.prev
;
189 if (hx
.BaseEquals (nx
))
190 hx
.kpm_next
= nx
.kpm_next
;
197 MulticastDelegate match
= haystack
;
201 while (nx
!= null && !nx
.BaseEquals (hx
)) {
206 nx
= nx
== null ? needle
: nx
.prev
;
214 } while (hx
!= null);
220 protected override Delegate
RemoveImpl (Delegate
value)
225 // match this with value
226 MulticastDelegate head
, tail
;
227 head
= KPM ((MulticastDelegate
)value, this, out tail
);
231 // duplicate chain without head..tail
232 MulticastDelegate prev
= null, retval
= null, orig
;
233 for (orig
= this; (object)orig
!= (object)head
; orig
= orig
.prev
) {
234 MulticastDelegate clone
= (MulticastDelegate
)orig
.Clone ();
241 for (orig
= tail
; (object)orig
!= null; orig
= orig
.prev
) {
242 MulticastDelegate clone
= (MulticastDelegate
)orig
.Clone ();
255 public static bool operator == (MulticastDelegate a
, MulticastDelegate b
)
257 if ((object)a
== null) {
258 if ((object)b
== null)
265 public static bool operator != (MulticastDelegate a
, MulticastDelegate b
)