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
10 // TODO: Remove Missing
13 using System.Collections;
14 using System.Globalization;
18 public abstract class MulticastDelegate : Delegate
20 private MulticastDelegate prev;
21 private MulticastDelegate kpm_next;
23 protected MulticastDelegate (object target, string method)
24 : base (target, method)
29 protected MulticastDelegate (Type target_type, string method)
30 : base (target_type, method)
36 private MulticastDelegate (Type target_type, string method, Delegate [] list)
37 : base (target_type, method)
39 invocation_list = (Delegate[])list.Clone ();
44 public MethodInfo Method {
51 public override object DynamicInvokeImpl( object[] args )
54 prev.DynamicInvokeImpl( args );
56 return base.DynamicInvokeImpl( args );
60 // Equals: two multicast delegates are equal if their base is equal
61 // and their invocations list is equal.
63 public override bool Equals (object o)
65 if ( ! base.Equals( o ) )
68 MulticastDelegate d = (MulticastDelegate) o;
70 if ( this.prev == null ) {
77 return this.prev.Equals( d.prev );
81 // FIXME: This could use some improvements.
83 public override int GetHashCode ()
85 return base.GetHashCode ();
89 // Return, in order of invocation, the invocation list
90 // of a MulticastDelegate
92 public override Delegate[] GetInvocationList()
95 for (d = (MulticastDelegate) this.Clone (); d.prev != null; d = d.prev)
98 if (d.kpm_next == null) {
99 MulticastDelegate other = (MulticastDelegate) d.Clone ();
101 other.kpm_next = null;
102 return new Delegate [1] { other };
104 ArrayList list = new ArrayList ();
105 for (; d != null; d = d.kpm_next) {
106 MulticastDelegate other = (MulticastDelegate) d.Clone ();
108 other.kpm_next = null;
112 return (Delegate []) list.ToArray (typeof (Delegate));
116 // Combines this MulticastDelegate with the (Multicast)Delegate `follow'.
117 // This does _not_ combine with Delegates. ECMA states the whole delegate
118 // thing should have better been a simple System.Delegate class.
119 // Compiler generated delegates are always MulticastDelegates.
121 protected override Delegate CombineImpl( Delegate follow )
123 MulticastDelegate combined, orig, clone;
125 if ( this.GetType() != follow.GetType() )
126 throw new ArgumentException( Locale.GetText("Incompatible Delegate Types") );
128 combined = (MulticastDelegate)follow.Clone();
130 for ( clone = combined, orig = ((MulticastDelegate)follow).prev;
131 orig != null; orig = orig.prev ) {
133 clone.prev = (MulticastDelegate)orig.Clone();
137 clone.prev = (MulticastDelegate)this.Clone();
139 for ( clone = clone.prev, orig = this.prev;
140 orig != null; orig = orig.prev ) {
142 clone.prev = (MulticastDelegate)orig.Clone();
149 private bool BaseEquals( MulticastDelegate value )
151 return base.Equals( value );
155 * Perform a slightly crippled version of
156 * Knuth-Pratt-Morris over MulticastDelegate chains.
157 * Border values are set as pointers in kpm_next;
158 * Generally, KPM border arrays are length n+1 for
159 * strings of n. This one works with length n at the
160 * expense of a few additional comparisions.
162 private static MulticastDelegate KPM( MulticastDelegate needle,
163 MulticastDelegate haystack,
164 out MulticastDelegate tail )
166 MulticastDelegate nx, hx;
170 nx = needle.kpm_next = null;
172 while ( nx != null && !nx.BaseEquals(hx) )
179 nx = nx == null ? needle : nx.prev;
180 if ( hx.BaseEquals(nx) )
181 hx.kpm_next = nx.kpm_next;
188 MulticastDelegate match = haystack;
192 while ( nx != null && !nx.BaseEquals(hx) ) {
197 nx = nx == null ? needle : nx.prev;
205 } while ( hx != null );
211 protected override Delegate RemoveImpl( Delegate value )
216 // match this with value
217 MulticastDelegate head, tail;
218 head = KPM((MulticastDelegate)value, this, out tail);
222 // duplicate chain without head..tail
223 MulticastDelegate prev = null, retval = null, orig;
224 for ( orig = this; (object)orig != (object)head; orig = orig.prev ) {
225 MulticastDelegate clone = (MulticastDelegate)orig.Clone();
232 for ( orig = tail; (object)orig != null; orig = orig.prev ) {
233 MulticastDelegate clone = (MulticastDelegate)orig.Clone();
246 public static bool operator == (MulticastDelegate a, MulticastDelegate b)
248 if ((object)a == null) {
249 if ((object)b == null)
256 public static bool operator != (MulticastDelegate a, MulticastDelegate b)