[build] Prevent cyclic targets from being built in parallel
[mono.git] / mcs / class / System / System.Collections.Specialized / NameValueCollection.cs
1 //
2 // System.Collections.Specialized.NameValueCollection.cs
3 //
4 // Author:
5 //   Gleb Novodran
6 //
7 // (C) Ximian, Inc.  http://www.ximian.com
8 // Copyright (C) 2004-2011 Novell (http://www.novell.com)
9 //
10
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System.Runtime.Serialization;
33 using System.Text;
34
35 namespace System.Collections.Specialized{
36
37         [Serializable]
38         public class NameValueCollection : NameObjectCollectionBase
39         {
40                 string[] cachedAllKeys = null;
41                 string[] cachedAll = null;
42
43                 //--------------------- Constructors -----------------------------
44
45                 public NameValueCollection () : base ()
46                 {
47                 }
48                 
49                 public NameValueCollection (int capacity) : base (capacity)
50                 {
51                 }
52                 
53                 public NameValueCollection (NameValueCollection col) : base (( col == null ) ? null : col.EqualityComparer ,
54                                                                              (col == null) ? null : col.Comparer, 
55                                                                              (col == null) ? null : col.HashCodeProvider)
56                 {
57                         if (col==null)
58                                 throw new ArgumentNullException ("col");                
59                         Add(col);
60                 }
61
62                 [Obsolete ("Use NameValueCollection (IEqualityComparer)")]
63                 public NameValueCollection (IHashCodeProvider hashProvider, IComparer comparer)
64                         : base (hashProvider, comparer)
65                 {
66                         
67                 }
68
69                 public NameValueCollection (int capacity, NameValueCollection col)
70                         : base (capacity, (col == null) ? null : col.HashCodeProvider, 
71                                         (col == null) ? null : col.Comparer)
72                 {
73                         Add (col);                      
74                 }
75
76                 protected NameValueCollection (SerializationInfo info, StreamingContext context)
77                         :base (info, context)
78                 {
79                         
80                 }
81                 
82                 [Obsolete ("Use NameValueCollection (IEqualityComparer)")]
83                 public NameValueCollection (int capacity, IHashCodeProvider hashProvider, IComparer comparer)
84                         :base (capacity, hashProvider, comparer)
85                 {
86                         
87                 }
88
89                 public NameValueCollection (IEqualityComparer equalityComparer)
90                         : base (equalityComparer)
91                 {
92                 }
93
94                 public NameValueCollection (int capacity, IEqualityComparer equalityComparer)
95                         : base (capacity, equalityComparer)
96                 {
97                 }
98
99                 public virtual string[] AllKeys 
100                 {
101                         get {
102                                 if (cachedAllKeys == null)
103                                         cachedAllKeys = BaseGetAllKeys ();
104                                 return this.cachedAllKeys;
105                         }
106                 }
107                 
108                 public string this [int index] 
109                 {
110                         get{
111                                 return this.Get (index);
112                         }
113                 }
114                 
115                 public string this [string name] {
116                         get{
117                                 return this.Get (name);
118                         }
119                         set{
120                                 this.Set (name,value);
121                         }
122                 }
123                 
124                 public void Add (NameValueCollection c)
125                 {
126                         if (this.IsReadOnly)
127                                 throw new NotSupportedException ("Collection is read-only");
128                         if (c == null)
129                                 throw new ArgumentNullException ("c");
130
131 // make sense - but it's not the exception thrown
132 //                              throw new ArgumentNullException ();
133                         
134                         InvalidateCachedArrays ();
135                         int max = c.Count;
136                         for (int i=0; i < max; i++){
137                                 string key = c.GetKey (i);
138                                 string[] values = c.GetValues (i);
139
140                                 if (values != null && values.Length > 0) {
141                                         foreach (string value in values)
142                                                 Add (key, value);
143                                 } else
144                                         Add (key, null);
145                         }
146                 }
147
148                 /// in SDK doc: If the same value already exists under the same key in the collection, 
149                 /// it just adds one more value in other words after
150                 /// <code>
151                 /// NameValueCollection nvc;
152                 /// nvc.Add ("LAZY","BASTARD")
153                 /// nvc.Add ("LAZY","BASTARD")
154                 /// </code>
155                 /// nvc.Get ("LAZY") will be "BASTARD,BASTARD" instead of "BASTARD"
156
157                 public virtual void Add (string name, string value)
158                 {
159                         if (this.IsReadOnly)
160                                 throw new NotSupportedException ("Collection is read-only");
161                         
162                         InvalidateCachedArrays ();
163                         ArrayList values = (ArrayList)BaseGet (name);
164                         if (values == null){
165                                 values = new ArrayList ();
166                                 if (value != null)
167                                         values.Add (value);
168                                 BaseAdd (name, values);
169                         }
170                         else {
171                                 if (value != null)
172                                         values.Add (value);
173                         }
174
175                 }
176
177                 public virtual void Clear ()
178                 {
179                         if (this.IsReadOnly)
180                                 throw new NotSupportedException ("Collection is read-only");
181                         InvalidateCachedArrays ();
182                         BaseClear ();
183                 }
184
185                 public void CopyTo (Array dest, int index)
186                 {
187                         if (dest == null)
188                                 throw new ArgumentNullException ("dest", "Null argument - dest");
189                         if (index < 0)
190                                 throw new ArgumentOutOfRangeException ("index", "index is less than 0");
191                         if (dest.Rank > 1)
192                                 throw new ArgumentException ("dest", "multidim");
193
194                         if (cachedAll == null)
195                                 RefreshCachedAll ();
196                         try {
197                                 cachedAll.CopyTo (dest, index);
198                         } catch (ArrayTypeMismatchException) {
199                                 throw new InvalidCastException();
200                         }
201                 }
202
203                 private void RefreshCachedAll ()
204                 {
205                         this.cachedAll = null;
206                         int max = this.Count;
207                         cachedAll = new string [max];
208                         for (int i = 0; i < max; i++)
209                                 cachedAll [i] = this.Get (i);
210                 }
211                 
212                 public virtual string Get (int index)
213                 {
214                         ArrayList values = (ArrayList)BaseGet (index);
215                         // if index is out of range BaseGet throws an ArgumentOutOfRangeException
216
217                         return AsSingleString (values);
218                 }
219                 
220                 public virtual string Get (string name)
221                 {
222                         ArrayList values = (ArrayList)BaseGet (name);
223                         return AsSingleString (values);
224                 }
225
226                 private static string AsSingleString (ArrayList values)
227                 {
228                         const char separator = ',';
229                         
230                         if (values == null)
231                                 return null;
232                         int max = values.Count;
233                         
234                         switch (max) {
235                         case 0:
236                                 return null;
237                         case 1:
238                                 return (string)values [0];
239                         case 2:
240                                 return String.Concat ((string)values [0], separator, (string)values [1]);
241                         default:
242                                 int len = max;
243                                 for (int i = 0; i < max; i++)
244                                         len += ((string)values [i]).Length;
245                                 StringBuilder sb = new StringBuilder ((string)values [0], len);
246                                 for (int i = 1; i < max; i++){
247                                         sb.Append (separator);
248                                         sb.Append (values [i]);
249                                 }
250
251                                 return sb.ToString ();
252                         }
253                 }
254                 
255                 
256                 public virtual string GetKey (int index)
257                 {
258                         return BaseGetKey (index);
259                 }
260                 
261                 
262                 public virtual string[] GetValues (int index)
263                 {
264                         ArrayList values = (ArrayList)BaseGet (index);
265                         
266                         return AsStringArray (values);
267                 }
268                 
269                 
270                 public virtual string[] GetValues (string name)
271                 {
272                         ArrayList values = (ArrayList)BaseGet (name);
273                         
274                         return AsStringArray (values);
275                 }
276                 
277                 private static string[] AsStringArray (ArrayList values)
278                 {
279                         if (values == null)
280                                 return null;
281                         int max = values.Count;//get_Count ();
282                         if (max == 0)
283                                 return null;
284                         
285                         string[] valArray = new string[max];
286                         values.CopyTo (valArray);
287                         return valArray;
288                 }
289                 
290                 public bool HasKeys ()
291                 {
292                         return BaseHasKeys ();
293                 }
294                 
295                 public virtual void Remove (string name)
296                 {
297                         if (this.IsReadOnly)
298                                 throw new NotSupportedException ("Collection is read-only");
299                         InvalidateCachedArrays ();
300                         BaseRemove (name);
301                         
302                 }
303                 
304                 public virtual void Set (string name, string value)
305                 {
306                         if (this.IsReadOnly)
307                                 throw new NotSupportedException ("Collection is read-only");
308
309                         InvalidateCachedArrays ();
310                         
311                         ArrayList values = new ArrayList ();
312                         if (value != null) {
313                                 values.Add (value);
314                                 BaseSet (name,values);
315                         }
316                         else {
317                                 // remove all entries
318                                 BaseSet (name, null);
319                         }
320                 }
321                 
322                 protected void InvalidateCachedArrays ()
323                 {
324                         cachedAllKeys = null;
325                         cachedAll = null;
326                 }
327
328         }
329 }