Merge pull request #615 from nealef/master
[mono.git] / mcs / class / corlib / System.Collections.ObjectModel / Collection.cs
1 // -*- Mode: csharp; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
2 //
3 // System.Collections.ObjectModel.Collection
4 //
5 // Authors:
6 //    Zoltan Varga (vargaz@gmail.com)
7 //    David Waite (mass@akuma.org)
8 //    Marek Safar (marek.safar@gmail.com)
9 //
10 // (C) 2005 Novell, Inc.
11 // (C) 2005 David Waite
12 //
13
14 //
15 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
16 // Copyright (C) 2005 David Waite
17 // Copyright (C) 2011 Xamarin, Inc (http://www.xamarin.com)
18 //
19 // Permission is hereby granted, free of charge, to any person obtaining
20 // a copy of this software and associated documentation files (the
21 // "Software"), to deal in the Software without restriction, including
22 // without limitation the rights to use, copy, modify, merge, publish,
23 // distribute, sublicense, and/or sell copies of the Software, and to
24 // permit persons to whom the Software is furnished to do so, subject to
25 // the following conditions:
26 // 
27 // The above copyright notice and this permission notice shall be
28 // included in all copies or substantial portions of the Software.
29 // 
30 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
31 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
32 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
33 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
34 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
35 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
36 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 //
38
39 using System;
40 using System.Collections;
41 using System.Collections.Generic;
42 using System.Runtime.InteropServices;
43 using System.Diagnostics;
44
45 namespace System.Collections.ObjectModel
46 {
47         [ComVisible (false)]
48         [Serializable]
49         [DebuggerDisplay ("Count={Count}")]
50         [DebuggerTypeProxy (typeof (CollectionDebuggerView<>))]
51         public class Collection<T> : IList<T>, IList
52 #if NET_4_5
53                 , IReadOnlyList<T>
54 #endif
55         {
56                 IList <T> list;
57                 object syncRoot;
58                 
59                 public Collection ()
60                 {
61                         List <T> l = new List <T> ();
62                         IList l2 = l as IList;
63                         syncRoot = l2.SyncRoot;
64                         list = l;
65                 }
66
67                 public Collection (IList <T> list)
68                 {
69                         if (list == null)
70                                 throw new ArgumentNullException ("list");
71                         this.list = list;
72                         ICollection l = list as ICollection;
73                         syncRoot = (l != null) ? l.SyncRoot : new object ();
74                 }
75
76                 public void Add (T item)
77                 {
78                         int idx = list.Count;
79                         InsertItem (idx, item);
80                 }
81
82                 public void Clear ()
83                 {
84                         ClearItems ();
85                 }
86
87                 protected virtual void ClearItems ()
88                 {
89                         list.Clear ();
90                 }
91
92                 public bool Contains (T item)
93                 {
94                         return list.Contains (item);
95                 }
96
97                 public void CopyTo (T [] array, int index)
98                 {
99                         list.CopyTo (array, index);
100                 }
101
102                 public IEnumerator <T> GetEnumerator ()
103                 {
104                         return list.GetEnumerator ();
105                 }
106
107                 public int IndexOf (T item)
108                 {
109                         return list.IndexOf (item);
110                 }
111
112                 public void Insert (int index, T item)
113                 {
114                         InsertItem (index, item);
115                 }
116
117                 protected virtual void InsertItem (int index, T item)
118                 {
119                         list.Insert (index, item);
120                 }
121
122                 protected IList<T> Items {
123                         get { return list; }
124                 }
125
126                 public bool Remove (T item)
127                 {
128                         int idx = IndexOf (item);
129                         if (idx == -1) 
130                                 return false;
131                         
132                         RemoveItem (idx);
133                         
134                         return true;
135                 }
136
137                 public void RemoveAt (int index)
138                 {
139                         RemoveItem (index);
140                 }
141
142                 protected virtual void RemoveItem (int index)
143                 {
144                         list.RemoveAt (index);
145                 }
146
147                 public int Count {
148                         get { return list.Count; }
149                 }
150
151                 public T this [int index] {
152                         get { return list [index]; }
153                         set { SetItem (index, value); }
154                 }
155
156                 bool ICollection<T>.IsReadOnly {
157                         get { return list.IsReadOnly; }
158                 }
159
160                 protected virtual void SetItem (int index, T item)
161                 {
162                         list[index] = item;
163                 }
164
165                 
166 #region Helper methods for non-generic interfaces
167                 
168                 internal static T ConvertItem (object item)
169                 {
170                         if (CollectionHelpers.IsValidItem<T> (item))
171                                 return (T)item;
172                         throw new ArgumentException ("item");
173                 }
174                 
175                 internal static void CheckWritable (IList <T> list)
176                 {
177                         if (list.IsReadOnly)
178                                 throw new NotSupportedException ();
179                 }
180                 
181                 internal static bool IsSynchronized (IList <T> list)
182                 {
183                         ICollection c = list as ICollection;
184                         return (c != null) ? c.IsSynchronized : false;
185                 }
186                 
187                 internal static bool IsFixedSize (IList <T> list)
188                 {
189                         IList l = list as IList;
190                         return (l != null) ? l.IsFixedSize : false;
191                 }
192 #endregion
193
194 #region Not generic interface implementations
195                 void ICollection.CopyTo (Array array, int index)
196                 {
197                         ((ICollection)list).CopyTo (array, index);
198                 }
199                 
200                 IEnumerator IEnumerable.GetEnumerator ()
201                 {
202                         return (IEnumerator) list.GetEnumerator ();
203                 }
204                                 
205                 int IList.Add (object value)
206                 {
207                         int idx = list.Count;
208                         InsertItem (idx, ConvertItem (value));
209                         return idx;
210                 }
211                 
212                 bool IList.Contains (object value)
213                 {
214                         if (CollectionHelpers.IsValidItem<T> (value))
215                                 return list.Contains ((T) value);
216                         return false;
217                 }
218                 
219                 int IList.IndexOf (object value)
220                 {
221                         if (CollectionHelpers.IsValidItem<T> (value))
222                                 return list.IndexOf ((T) value);
223                         return -1;
224                 }
225                 
226                 void IList.Insert (int index, object value)
227                 {
228                         InsertItem (index, ConvertItem (value));
229                 }
230                 
231                 void IList.Remove (object value)
232                 {
233                         CheckWritable (list);
234
235                         int idx = IndexOf (ConvertItem (value));
236
237                         RemoveItem (idx);
238                 }
239                 
240                 bool ICollection.IsSynchronized {
241                         get { return IsSynchronized (list); }
242                 }
243                 
244                 object ICollection.SyncRoot {
245                         get { return syncRoot; }
246                 }
247                 bool IList.IsFixedSize {
248                         get { return IsFixedSize (list); }
249                 }
250                 
251                 bool IList.IsReadOnly {
252                         get { return list.IsReadOnly; }
253                 }
254                 
255                 object IList.this [int index] {
256                         get { return list [index]; }
257                         set { SetItem (index, ConvertItem (value)); }
258                 }
259 #endregion
260         }
261
262         static class CollectionHelpers
263         {
264                 public static bool IsValidItem<T> (object item)
265                 {
266                         return item is T || (item == null && ! typeof (T).IsValueType);
267                 }
268         }
269 }