* Hashtable.cs (Find): Before calling KeyEquals, check to see if k
[mono.git] / mcs / class / corlib / System.Collections / DictionaryBase.cs
1 //
2 // System.Collections.DictionaryBase.cs
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //
7 // (C) Ximian, Inc.  http://www.ximian.com
8 //
9
10 //
11 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 using System;
34
35 namespace System.Collections {
36
37         /// <summary>
38         ///   An abstract class that provides a simple way to monitor changes to a
39         ///   Hashtable.  Derived classes overwrite one or more of the `On' methods
40         ///   to track the changes to the Hashtable.
41         /// </summary>
42         ///
43         /// <remarks>
44         ///   This class is a base class that can simplify the development of
45         ///   strongly typed collections.  The idea being that the insertion of elements
46         ///   into the Hashtable can be forced to be of a given type.
47         ///
48         ///   The `On' members are protected and designed to be used only by derived
49         ///   classes.
50         /// </remarks>
51         [Serializable]
52         public abstract class DictionaryBase : IDictionary, ICollection, IEnumerable {
53
54                 Hashtable hashtable;
55                 
56                 protected DictionaryBase ()
57                 {
58                         hashtable = new Hashtable ();
59                 }
60
61                 /// <summary>
62                 ///   Clears the contents of the dictionary
63                 /// </summary>
64                 public void Clear ()
65                 {
66                         OnClear ();
67                         hashtable.Clear ();
68                         OnClearComplete ();
69                 }
70
71                 /// <summary>
72                 ///   Returns the number of items in the dictionary
73                 /// </summary>
74                 public int Count {
75                         get {
76                                 return hashtable.Count;
77                         }
78                 }
79
80                 /// <summary>
81                 ///   The collection contained as an IDictionary
82                 /// </summary>
83                 protected IDictionary Dictionary {
84                         get {
85                                 return this;
86                         }
87                 }
88
89                 /// <summary>
90                 ///   The internal Hashtable representation for this dictionary
91                 /// </summary>
92                 protected Hashtable InnerHashtable {
93                         get {
94                                 return hashtable;
95                         }
96                 }
97
98                 /// <summary>
99                 ///   Copies the contents of the Dictionary into the target array
100                 /// </summary>
101                 /// <param name="array">
102                 ///   The array to copy the contents of the dictionary to.  The
103                 ///   array must have a zero-based indexing
104                 /// </param>
105                 /// <param name="index">
106                 ///   Starting index within the array where to copy the objects
107                 ///   to.
108                 /// </param>
109                 public void CopyTo (Array array, int index)
110                 {
111                         if (array == null)
112                                 throw new ArgumentNullException ("array");
113                         if (index < 0)
114                                 throw new ArgumentOutOfRangeException ("index must be possitive");
115                         if (array.Rank > 1)
116                                 throw new ArgumentException ("array is multidimensional");
117                         int size = array.Length;
118                         if (index > size)
119                                 throw new ArgumentException ("index is larger than array size");
120                         if (index + Count > size)
121                                 throw new ArgumentException ("Copy will overlflow array");
122
123                         DoCopy (array, index);
124                 }
125
126                 /// <summary>
127                 ///   Internal routine called by CopyTo to perform the actual
128                 ///   copying of the data
129                 /// </summary>
130                 private void DoCopy (Array array, int index)
131                 {
132                         foreach (DictionaryEntry de in hashtable)
133                                 array.SetValue (de, index++);
134                 }
135
136                 /// <summary>
137                 ///   Returns an enumerator for the dictionary
138                 /// </summary>
139                 public IDictionaryEnumerator GetEnumerator ()
140                 {
141                         return hashtable.GetEnumerator ();
142                 }
143
144                 /// <summary>
145                 ///   Hook invoked before the clear operation
146                 ///   is performed on the DictionaryBase
147                 /// </summary>
148                 protected virtual void OnClear ()
149                 {
150                 }
151
152                 /// <summary>
153                 ///   Hook invoked after the clear operation
154                 ///   is performed on the DictionaryBase
155                 /// </summary>
156                 ///
157                 /// <remarks>
158                 ///   The default implementation does nothing, derived classes
159                 ///   can override this method to be notified of changes
160                 /// </remarks>
161                 protected virtual void OnClearComplete ()
162                 {
163                 }
164
165                 /// <summary>
166                 ///   Hook invoked while fetching data from the DictionaryBase.
167                 /// </summary>
168                 ///
169                 /// <remarks>
170                 ///   This method is provided as a simple way to override the values
171                 ///   returned by the DictionaryBase. 
172                 /// </remarks>
173                 ///
174                 /// <param name="key">Key of the object to retrieve</param>
175                 /// <param name="current_value">Current value of the object associated with
176                 /// <paramref name="key"/></param>
177                 protected virtual object OnGet (object key, object current_value)
178                 {
179                         return current_value;
180                 }
181
182                 /// <summary>
183                 ///   Hook invoked before inserting data into the DictionaryBase.
184                 /// </summary>
185                 ///
186                 /// <remarks>
187                 ///   Derived classes can override this method and perform some
188                 ///   action before the <paramref name="current_value"/> is inserted
189                 ///   into the dictionary.
190                 ///
191                 ///   The default implementation does nothing, derived classes
192                 ///   can override this method to be notified of changes
193                 /// </remarks>
194                 ///
195                 /// <param name="key">Key of the object to insert</param>
196                 /// <param name="current_value">Current value of the object associated with
197                 /// <paramref name="key"/></param>
198                 protected virtual void OnInsert (object key, object current_value)
199                 {
200                 }
201                 
202                 /// <summary>
203                 ///   Hook invoked after inserting the data into the DictionaryBase
204                 /// </summary>
205                 ///
206                 /// <remarks>
207                 ///   The default implementation does nothing, derived classes
208                 ///   can override this method to be notified of changes
209                 /// </remarks>
210                 ///
211                 /// <param name="key">Key of the object to insert</param>
212                 /// <param name="current_value">Current value of the object associated with
213                 /// <paramref name="key"/></param>
214                 protected virtual void OnInsertComplete (object key, object current_value)
215                 {
216                 }
217
218                 /// <summary>
219                 ///   Hook invoked before changing a value for a key in the DictionaryBase.
220                 /// </summary>
221                 ///
222                 /// <remarks>
223                 ///   Derived classes can override this method and perform some
224                 ///   action before the <paramref name="current_value"/> is changed
225                 ///   in the dictionary.  
226                 /// </remarks>
227                 ///
228                 /// <param name="key">Key of the object to change</param>
229                 /// <param name="current_value">Current value of the object associated with
230                 /// <paramref name="key"/></param>
231                 protected virtual void OnSet (object key, object current_value, object new_value)
232                 {
233                 }
234                 
235                 /// <summary>
236                 ///   Hook invoked after changing a value for a key in the DictionaryBase.
237                 /// </summary>
238                 ///
239                 /// <remarks>
240                 ///   The default implementation does nothing, derived classes
241                 ///   can override this method to be notified of changes
242                 /// </remarks>
243                 ///
244                 /// <param name="key">Key of the object to change</param>
245                 /// <param name="current_value">Current value of the object associated with
246                 /// <paramref name="key"/></param>
247                 protected virtual void OnSetComplete (object key, object current_value, object new_value)
248                 {
249                 }
250
251                 /// <summary>
252                 ///   Hook invoked before removing a key/value from the DictionaryBase.
253                 /// </summary>
254                 ///
255                 /// <remarks>
256                 ///   Derived classes can override this method and perform some
257                 ///   action before the <paramref name="current_value"/> is removed
258                 ///   from the dictionary.  
259                 /// </remarks>
260                 ///
261                 /// <param name="key">Key of the object to remove</param>
262                 /// <param name="current_value">Current value of the object associated with
263                 /// <paramref name="key"/></param>
264                 protected virtual void OnRemove (object key, object current_value)
265                 {
266                 }
267                 
268                 /// <summary>
269                 ///   Hook invoked after removing a key/value from the DictionaryBase.
270                 /// </summary>
271                 ///
272                 /// <remarks>
273                 ///   The default implementation does nothing, derived classes
274                 ///   can override this method to be notified of changes.
275                 /// </remarks>
276                 ///
277                 /// <param name="key">Key of the object to remove</param>
278                 /// <param name="current_value">Current value of the object associated with
279                 /// <paramref name="key"/></param>
280                 protected virtual void OnRemoveComplete (object key, object current_value)
281                 {
282                 }
283                 
284                 /// <summary>
285                 ///   Hook invoked after the value has been validated
286                 /// </summary>
287                 ///
288                 /// <remarks>
289                 ///   The default implementation does nothing, derived classes
290                 ///   can override this method to monitor the DictionaryBase.
291                 /// </remarks>
292                 ///
293                 /// <param name="key">Key of the object to retrieve</param>
294                 /// <param name="current_value">Current value of the object associated with
295                 /// <paramref name="key"/></param>
296                 protected virtual void OnValidate (object key, object current_value)
297                 {
298                 }
299
300                 bool IDictionary.IsFixedSize {
301                         get {
302                                 return false;
303                         }
304                 }
305
306                 bool IDictionary.IsReadOnly {
307                         get {
308                                 return false;
309                         }
310                 }
311
312                 object IDictionary.this [object key] {
313                         get {
314                                 OnGet (key, hashtable [key]);
315                                 object value = hashtable [key];
316                                 return value;
317                         }
318
319                         set {
320                                 OnValidate (key, value);
321                                 object current_value = hashtable [key];
322                                 OnSet (key, current_value, value);
323                                 hashtable [key] = value;
324                                 try {
325                                         OnSetComplete (key, current_value, value);
326                                 } catch {
327                                         hashtable [key] = current_value;
328                                         throw;
329                                 }
330                         }
331                 }
332
333                 ICollection IDictionary.Keys {
334                         get {
335                                 return hashtable.Keys;
336                         }
337                 }
338
339                 ICollection IDictionary.Values {
340                         get {
341                                 return hashtable.Values;
342                         }
343                 }
344
345                 /// <summary>
346                 ///   Adds a key/value pair to the dictionary.
347                 /// </summary>
348                 void IDictionary.Add (object key, object value)
349                 {
350                         OnValidate (key, value);
351                         OnInsert (key, value);
352                         hashtable.Add (key, value);
353                         try {
354                                 OnInsertComplete (key, value);
355                         } catch {
356                                 hashtable.Remove (key);
357                                 throw;
358                         }
359                 }
360
361                 /// <summary>
362                 ///   Removes a Dictionary Entry based on its key
363                 /// </summary>
364                 void IDictionary.Remove (object key)
365                 {
366                         object value = hashtable [key];
367                         OnValidate (key, value);
368                         OnRemove (key, value);
369                         hashtable.Remove (key);
370                         OnRemoveComplete (key, value);
371                 }
372
373                 /// <summary>
374                 ///   Tests whether the dictionary contains an entry
375                 /// </summary>
376                 bool IDictionary.Contains (object key)
377                 {
378                         return hashtable.Contains (key);
379                 }
380
381                 bool ICollection.IsSynchronized {
382                         get {
383                                 return hashtable.IsSynchronized;
384                         }
385                 }
386
387                 object ICollection.SyncRoot {
388                         get {
389                                 return hashtable.SyncRoot;
390                         }
391                 }
392
393                 IEnumerator IEnumerable.GetEnumerator ()
394                 {
395                         return hashtable.GetEnumerator ();
396                 }
397         }
398 }