2003-05-09 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / corlib / System / MulticastDelegate.cs
1 //
2 // System.MultiCastDelegate.cs
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //   Daniel Stodden (stodden@in.tum.de)
7 //
8 // (C) Ximian, Inc.  http://www.ximian.com
9 //
10 // TODO: Remove Missing
11 //
12
13 using System.Collections;
14 using System.Globalization;
15
16 namespace System {
17
18         public abstract class MulticastDelegate : Delegate
19         {
20                 private MulticastDelegate prev;
21                 private MulticastDelegate kpm_next;
22
23                 protected MulticastDelegate (object target, string method)
24                         : base (target, method)
25                 {
26                         prev = null;
27                 }
28
29                 protected MulticastDelegate (Type target_type, string method)
30                         : base (target_type, method)
31                 {
32                         prev = null;
33                 }
34
35 #if NOTYET
36                 private MulticastDelegate (Type target_type, string method, Delegate [] list)
37                         : base (target_type, method)
38                 {
39                         invocation_list = (Delegate[])list.Clone ();
40                 }
41 #endif
42                 
43 #if NOTYET
44                 public MethodInfo Method {
45                         get {
46                                 return null;
47                         }
48                 }
49 #endif
50
51                 public override object DynamicInvokeImpl( object[] args )
52                 {
53                         if ( prev != null )
54                                 prev.DynamicInvokeImpl( args );
55
56                         return base.DynamicInvokeImpl( args );
57                 }
58
59                 // <remarks>
60                 //   Equals: two multicast delegates are equal if their base is equal
61                 //   and their invocations list is equal.
62                 // </remarks>
63                 public override bool Equals (object o)
64                 {
65                         if ( ! base.Equals( o ) )
66                                 return false;
67
68                         MulticastDelegate d = (MulticastDelegate) o;
69
70                         if ( this.prev == null ) {
71                                 if ( d.prev == null )
72                                         return true;
73                                 else
74                                         return false;
75                         }
76
77                         return this.prev.Equals( d.prev );
78                 }
79                 
80                 //
81                 // FIXME: This could use some improvements.
82                 //
83                 public override int GetHashCode ()
84                 {
85                         return base.GetHashCode ();
86                 }
87                 
88                 // <summary>
89                 //   Return, in order of invocation, the invocation list
90                 //   of a MulticastDelegate
91                 // </summary>
92                 public override Delegate[] GetInvocationList()
93                 {
94                         MulticastDelegate d;
95                         for (d = (MulticastDelegate) this.Clone (); d.prev != null; d = d.prev)
96                                 d.prev.kpm_next = d;
97
98                         if (d.kpm_next == null) {
99                                 MulticastDelegate other = (MulticastDelegate) d.Clone ();
100                                 other.prev = null;
101                                 other.kpm_next = null;                          
102                                 return new Delegate [1] { other };
103                         }
104                         ArrayList list = new ArrayList ();
105                         for (; d != null; d = d.kpm_next) {
106                                 MulticastDelegate other = (MulticastDelegate) d.Clone ();
107                                 other.prev = null;
108                                 other.kpm_next = null;
109                                 list.Add (other);
110                         }
111
112                         return (Delegate []) list.ToArray (typeof (Delegate));
113                 }
114
115                 // <summary>
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.
120                 // </summary>
121                 protected override Delegate CombineImpl( Delegate follow )
122                 {
123                         MulticastDelegate combined, orig, clone;
124                         
125                         if ( this.GetType() != follow.GetType() )
126                                 throw new ArgumentException( Locale.GetText("Incompatible Delegate Types") );
127
128                         combined = (MulticastDelegate)follow.Clone();
129
130                         for ( clone = combined, orig = ((MulticastDelegate)follow).prev;
131                               orig != null; orig = orig.prev ) {
132                                 
133                                 clone.prev = (MulticastDelegate)orig.Clone();
134                                 clone = clone.prev;
135                         }
136
137                         clone.prev = (MulticastDelegate)this.Clone();
138
139                         for ( clone = clone.prev, orig = this.prev;
140                               orig != null; orig = orig.prev ) {
141
142                                 clone.prev = (MulticastDelegate)orig.Clone();
143                                 clone = clone.prev;
144                         }
145
146                         return combined;
147                 }
148                 
149                 private bool BaseEquals( MulticastDelegate value )
150                 {
151                         return base.Equals( value );
152                 }
153
154                 /* 
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.
161                  */
162                 private static MulticastDelegate KPM( MulticastDelegate needle,
163                                                       MulticastDelegate haystack,
164                                                       out MulticastDelegate tail )
165                 { 
166                         MulticastDelegate nx, hx;
167                         
168                         // preprocess
169                         hx = needle;
170                         nx = needle.kpm_next = null;
171                         do {
172                                 while ( nx != null && !nx.BaseEquals(hx) )
173                                         nx = nx.kpm_next;
174
175                                 hx = hx.prev;
176                                 if (hx == null)
177                                         break;
178                                         
179                                 nx = nx == null ? needle : nx.prev;
180                                 if ( hx.BaseEquals(nx) )
181                                         hx.kpm_next = nx.kpm_next;
182                                 else
183                                         hx.kpm_next = nx;
184
185                         } while (true);
186
187                         // match
188                         MulticastDelegate match = haystack;
189                         nx = needle;
190                         hx = haystack;
191                         do {
192                                 while ( nx != null && !nx.BaseEquals(hx) ) {
193                                         nx = nx.kpm_next;
194                                         match = match.prev;
195                                 }
196
197                                 nx = nx == null ? needle : nx.prev;
198                                 if ( nx == null ) {
199                                         // bingo
200                                         tail = hx.prev;
201                                         return match;
202                                 }
203                                 
204                                 hx = hx.prev;
205                         } while ( hx != null );
206
207                         tail = null;
208                         return null;
209                 }
210
211                 protected override Delegate RemoveImpl( Delegate value )
212                 {
213                         if ( value == null )
214                                 return this;
215
216                         // match this with value
217                         MulticastDelegate head, tail;
218                         head = KPM((MulticastDelegate)value, this, out tail);
219                         if ( head == null )
220                                 return this;
221                         
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();
226                                 if ( prev != null )
227                                         prev.prev = clone;
228                                 else
229                                         retval = clone;
230                                 prev = clone;
231                         }
232                         for ( orig = tail; (object)orig != null; orig = orig.prev ) {
233                                 MulticastDelegate clone = (MulticastDelegate)orig.Clone();
234                                 if ( prev != null )
235                                         prev.prev = clone;
236                                 else
237                                         retval = clone;
238                                 prev = clone;
239                         }
240                         if ( prev != null )
241                                 prev.prev = null;
242
243                         return retval;
244                 }
245
246                 public static bool operator == (MulticastDelegate a, MulticastDelegate b) 
247                 {
248                         if ((object)a == null) {
249                                 if ((object)b == null)
250                                         return true;
251                                 return false;
252                         }
253                         return a.Equals (b);
254                 }
255                 
256                 public static bool operator != (MulticastDelegate a, MulticastDelegate b) 
257                 {
258                         return !(a == b);
259                 }
260         }
261 }