Miscellaneous minor compliancy fixes:
[mono.git] / mcs / class / corlib / System / Array.cs
1
2 // System.Array.cs
3 //
4 // Authors:
5 //   Joe Shaw (joe@ximian.com)
6 //   Martin Baulig (martin@gnome.org)
7 //   Dietmar Maurer (dietmar@ximian.com)
8 //
9 // (C) 2001 Ximian, Inc.  http://www.ximian.com
10 //
11
12 using System.Collections;
13 using System.Runtime.CompilerServices;
14
15 namespace System
16 {
17
18         [Serializable]
19         public abstract class Array : ICloneable, ICollection, IList, IEnumerable
20         {
21                 // Constructor          
22                 private Array ()
23                 {
24                         /* empty */
25                 }
26                 
27                 // Properties
28                 public int Length 
29                 {
30                         get 
31                         {
32                                 int length = this.GetLength (0);
33
34                                 for (int i = 1; i < this.Rank; i++) {
35                                         length *= this.GetLength (i); 
36                                 }
37                                 
38                                 return length;
39                         }
40                 }
41
42                 public int Rank 
43                 {
44                         get
45                         {
46                                 return this.GetRank ();
47                         }
48                 }
49
50                 // IList interface
51                 object IList.this [int index] {
52                         get {
53                                 return GetValueImpl (index);
54                         } 
55                         set {
56                                 SetValueImpl (value, index);
57                         }
58                 }
59
60                 int IList.Add (object value) {
61                         throw new NotSupportedException ();
62                 }
63
64                 void IList.Clear () {
65                         Array.Clear (this, this.GetLowerBound(0), this.Length);
66                 }
67
68                 bool IList.Contains (object value) {
69                         if (this.Rank > 1)
70                                 throw new RankException ("Only single dimension arrays are supported.");
71
72                         int length = this.Length;
73                         for (int i = 0; i < length; i++) {
74                                 if (value.Equals (this.GetValueImpl (i)))
75                                         return true;
76                         }
77                         return false;
78                 }
79
80                 int IList.IndexOf (object value) {
81                         if (this.Rank > 1)
82                                 throw new RankException ();
83
84                         int length = this.Length;
85                         for (int i = 0; i < length; i++) {
86                                 if (value.Equals (this.GetValueImpl (i)))
87                                         // array index may not be zero-based.
88                                         // use lower bound
89                                         return i + this.GetLowerBound (0);
90                         }
91
92                         int retVal;
93                         unchecked {
94                                 // lower bound may be MinValue
95                                 retVal = this.GetLowerBound (0) - 1;
96                         }
97
98                         return retVal;
99                 }
100
101                 void IList.Insert (int index, object value) {
102                         throw new NotSupportedException ();
103                 }
104
105                 void IList.Remove (object value) {
106                         throw new NotSupportedException ();
107                 }
108
109                 void IList.RemoveAt (int index) {
110                         throw new NotSupportedException ();
111                 }
112
113                 // InternalCall Methods
114                 
115                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
116                 private extern int GetRank ();
117
118                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
119                 public extern int GetLength (int dimension);
120
121                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
122                 public extern int GetLowerBound (int dimension);
123
124                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
125                 public extern object GetValue (int[] idxs);
126
127                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
128                 public extern void SetValue (object value, int[] idxs);
129
130                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
131                 internal extern object GetValueImpl (int pos);
132
133                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
134                 internal extern void SetValueImpl (object value, int pos);
135
136                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
137                 internal extern static void FastCopy (Array source, int source_idx, Array dest, int dest_idx, int length);\r
138 \r
139                 [MethodImplAttribute(MethodImplOptions.InternalCall)]\r
140                 internal extern static Array CreateInstanceImpl(Type elementType, int[] lengths, int [] bounds);
141
142                 // Properties
143                 int ICollection.Count {
144                         get {
145                                 return Length;
146                         }
147                 }
148
149                 [MonoTODO]
150                 public virtual bool IsSynchronized {
151                         get {
152                                 // FIXME?
153                                 return false;
154                         }
155                 }
156
157                 [MonoTODO]
158                 public virtual object SyncRoot {
159                         get {
160                                 // FIXME
161                                 return null;
162                         }
163                 }
164
165                 public virtual bool IsFixedSize 
166                 {
167                         get {
168                                 return true;
169                         }
170                 }
171
172                 public virtual bool IsReadOnly 
173                 {
174                         get{
175                                 return false;
176                         }
177                 }
178
179                 public virtual IEnumerator GetEnumerator ()
180                 {
181                         return new SimpleEnumerator(this);
182                 }
183
184                 public int GetUpperBound (int dimension)
185                 {
186                         return GetLowerBound (dimension) +
187                                 GetLength (dimension) - 1;
188                 }
189
190                 public object GetValue (int idx)
191                 {
192                         int[] ind = new int [1];
193
194                         ind [0] = idx;
195
196                         return GetValue (ind);
197                 }
198
199                 public object GetValue (int idx1, int idx2)
200                 {
201                         int[] ind = new int [2];
202
203                         ind [0] = idx1;
204                         ind [1] = idx2;
205
206                         return GetValue (ind);
207                 }
208
209                 public object GetValue (int idx1, int idx2, int idx3)
210                 {
211                         int[] ind = new int [3];
212
213                         ind [0] = idx1;
214                         ind [1] = idx2;
215                         ind [2] = idx3;
216
217                         return GetValue (ind);
218                 }
219
220                 // This function is currently unused, but just in case we need it later on ... */
221                 internal int IndexToPos (int[] idxs)
222                 {
223                         if (idxs == null)
224                                 throw new ArgumentNullException ();
225
226                         if ((idxs.Rank != 1) || (idxs.Length != Rank))
227                                 throw new ArgumentException ();
228
229                         if ((idxs [0] < GetLowerBound (0)) || (idxs [0] > GetUpperBound (0)))
230                                 throw new IndexOutOfRangeException();
231
232                         int pos = idxs [0] - GetLowerBound (0);
233                         for (int i = 1; i < Rank; i++) {
234                                 if ((idxs [i] < GetLowerBound (i)) || (idxs [i] > GetUpperBound (i)))
235                                         throw new IndexOutOfRangeException();
236
237                                 pos *= GetLength (i);
238                                 pos += idxs [i] - GetLowerBound (i);
239                         }
240
241                         return pos;
242                 }
243
244                 public void SetValue (object value, int idx)
245                 {
246                         int[] ind = new int [1];
247
248                         ind [0] = idx;
249
250                         SetValue (value, ind);
251                 }
252                 
253                 public void SetValue (object value, int idx1, int idx2)
254                 {
255                         int[] ind = new int [2];
256
257                         ind [0] = idx1;
258                         ind [1] = idx2;
259
260                         SetValue (value, ind);
261                 }
262
263                 public void SetValue (object value, int idx1, int idx2, int idx3)
264                 {
265                         int[] ind = new int [3];
266
267                         ind [0] = idx1;
268                         ind [1] = idx2;
269                         ind [2] = idx3;
270
271                         SetValue (value, ind);
272                 }
273
274                 public static Array CreateInstance(Type elementType, int length)
275                 {
276                         int[] lengths = new int [1];
277                         int[] bounds = null;
278                         
279                         lengths [0] = length;
280                         
281                         return CreateInstanceImpl (elementType, lengths, bounds);
282                 }
283                 
284                 public static Array CreateInstance(Type elementType, int l1, int l2)
285                 {
286                         int[] lengths = new int [2];
287                         int[] bounds = null;
288                         
289                         lengths [0] = l1;
290                         lengths [1] = l2;
291                         
292                         return CreateInstanceImpl (elementType, lengths, bounds);
293                 }
294
295                 public static Array CreateInstance(Type elementType, int l1, int l2, int l3)
296                 {
297                         int[] lengths = new int [3];
298                         int[] bounds = null;
299                         
300                         lengths [0] = l1;
301                         lengths [1] = l2;
302                         lengths [2] = l3;
303                 
304                         return CreateInstanceImpl (elementType, lengths, bounds);
305                 }
306
307                 public static Array CreateInstance(Type elementType, int[] lengths)
308                 {
309                         int[] bounds = null;
310                         
311                         return CreateInstanceImpl (elementType, lengths, bounds);
312                 }
313
314                 public static Array CreateInstance(Type elementType, int[] lengths, int [] bounds)
315                 {
316                         if (bounds == null)
317                                 throw new ArgumentNullException("bounds");
318
319                         return CreateInstanceImpl (elementType, lengths, bounds);
320                 }
321
322                 
323                 public static int BinarySearch (Array array, object value)
324                 {
325                         if (array == null)
326                                 throw new ArgumentNullException("array");
327
328                         if (array.Rank > 1)
329                                 throw new RankException();
330
331                         if (!(value is IComparable))
332                                 throw new ArgumentException("value does not support IComparable");
333
334                         return BinarySearch (array, array.GetLowerBound (0), array.GetLength (0),
335                                              value, null);
336                 }
337
338                 public static int BinarySearch (Array array, object value, IComparer comparer)
339                 {
340                         if (array == null)
341                                 throw new ArgumentNullException("array");
342
343                         if (array.Rank > 1)
344                                 throw new RankException();
345
346                         if ((comparer == null) && !(value is IComparable))
347                                 throw new ArgumentException("comparer is null and value does not support IComparable");
348
349                         return BinarySearch (array, array.GetLowerBound (0), array.GetLength (0),
350                                              value, comparer);
351                 }
352
353                 public static int BinarySearch (Array array, int index, int length, object value)
354                 {
355                         if (array == null)
356                                 throw new ArgumentNullException("array");
357
358                         if (array.Rank > 1)
359                                 throw new RankException();
360
361                         if (index < array.GetLowerBound (0))
362                                 throw new ArgumentOutOfRangeException("index is less than the lower bound of array.");
363                         if (length < 0)
364                                 throw new ArgumentOutOfRangeException("length is less than zero.");
365
366                         if (index + length > array.GetLowerBound (0) + array.GetLength (0))
367                                 throw new ArgumentException("index and length do not specify a valid range in array.");
368                         if (!(value is IComparable))
369                                 throw new ArgumentException("value does not support IComparable");
370
371                         return BinarySearch (array, index, length, value, null);
372                 }
373
374                 public static int BinarySearch (Array array, int index,
375                                                 int length, object value,
376                                                 IComparer comparer)
377                 {
378                         if (array == null)
379                                 throw new ArgumentNullException ("array");
380
381                         if (array.Rank > 1)
382                                 throw new RankException ();
383
384                         if (index < array.GetLowerBound (0))
385                                 throw new ArgumentOutOfRangeException("index is less than the lower bound of array.");
386                         if (length < 0)
387                                 throw new ArgumentOutOfRangeException("length is less than zero.");
388
389                         if (index + length > array.GetLowerBound (0) + array.GetLength (0))
390                                 throw new ArgumentException("index and length do not specify a valid range in array.");
391
392                         if ((comparer == null) && !(value is IComparable))
393                                 throw new ArgumentException("comparer is null and value does not support IComparable");
394
395                         // cache this in case we need it
396                         IComparable valueCompare = value as IComparable;
397
398                         int iMin = index;
399                         int iMax = index + length;
400                         int iCmp = 0;
401                         try
402                         {
403                                 // there's a subtle balance here between
404                                 // 1) the while condition
405                                 // 2) the rounding down of the '/ 2'
406                                 // 3) the asymetrical recursion
407                                 // 4) the fact that iMax starts beyond the end of the array
408                                 while (iMin < iMax)
409                                 {
410                                         int iMid = (iMin + iMax) / 2;
411                                         object elt = array.GetValueImpl (iMid);
412
413                                         // this order is from MSDN
414                                         if (comparer != null)
415                                                 iCmp = comparer.Compare (value, elt);
416                                         else
417                                         {
418                                                 IComparable eltCompare = elt as IComparable;
419                                                 if (eltCompare != null)
420                                                         iCmp = -eltCompare.CompareTo (value);
421                                                 else
422                                                         iCmp = valueCompare.CompareTo (elt);
423                                         }
424
425                                         if (iCmp == 0)
426                                                 return iMid;
427                                         else if (iCmp < 0)
428                                                 iMax = iMid;
429                                         else
430                                                 iMin = iMid + 1;        // compensate for the rounding down
431                                 }
432                         }
433                         catch (InvalidCastException e)
434                         {
435                                 throw new ArgumentException ("array", e);
436                         }
437
438                         if (iCmp > 0)
439                                 return ~iMax;
440                         else
441                                 return ~iMin;
442                 }
443
444                 public static void Clear (Array array, int index, int length)
445                 {
446                         if (array == null)
447                                 throw new ArgumentNullException ();
448
449                         if (array.Rank > 1)
450                                 throw new RankException ();
451
452                         if (index < array.GetLowerBound (0) || length < 0 ||
453                                 index + length > array.GetUpperBound (0) + 1)
454                                 throw new ArgumentOutOfRangeException ();
455
456                         for (int i = 0; i < length; i++) 
457                         {
458                                 array.SetValueImpl(null, index + i);
459                         }
460                 }
461
462                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
463                 public virtual extern object Clone ();
464
465                 public static void Copy (Array source, Array dest, int length)
466                 {
467                         // need these checks here because we are going to use
468                         // GetLowerBound() on source and dest.
469                         if (source == null)
470                                 throw new ArgumentNullException ("null");
471
472                         if (dest == null)
473                                 throw new ArgumentNullException ("dest");
474
475                         Copy (source, source.GetLowerBound (0), dest, dest.GetLowerBound (0), length);                  
476                 }
477
478                 public static void Copy (Array source, int source_idx, Array dest, int dest_idx, int length)
479                 {
480                         if (source == null)
481                                 throw new ArgumentNullException ("null");
482
483                         if (dest == null)
484                                 throw new ArgumentNullException ("dest");
485
486                         if (length < 0)
487                                 throw new ArgumentOutOfRangeException ("length");
488
489                         if (source_idx < 0)
490                                 throw new ArgumentException ("source_idx");
491
492                         if (dest_idx < 0)
493                                 throw new ArgumentException ("dest_idx");
494
495                         int source_pos = source_idx - source.GetLowerBound (0);
496                         int dest_pos = dest_idx - dest.GetLowerBound (0);
497
498
499                         if (source_pos + length > source.Length || dest_pos + length > dest.Length)
500                                 throw new ArgumentException ("length");
501
502                         if (source.Rank != dest.Rank)
503                                 throw new RankException ();
504
505                         Type src_type = source.GetType ().GetElementType ();
506                         Type dst_type = dest.GetType ().GetElementType ();
507
508                         if (src_type == dst_type) {
509                                 FastCopy (source, source_pos, dest, dest_pos, length);
510                                 return;
511                         }
512
513                         if (!Object.ReferenceEquals (source, dest) || source_pos > dest_pos)
514                         {
515                                 for (int i = 0; i < length; i++) 
516                                 {
517                                         Object srcval = source.GetValueImpl (source_pos + i);
518
519                                         try {
520                                                 dest.SetValueImpl (srcval, dest_pos + i);
521                                         } catch {
522                                                 if ((dst_type.IsValueType || dst_type.Equals (typeof (String))) &&
523                                                         (src_type.Equals (typeof (Object))))
524                                                         throw new InvalidCastException ();
525                                                 else
526                                                         throw new ArrayTypeMismatchException (
527                                                                 String.Format ("(Types: source={0};  target={1})", src_type.FullName, dst_type.FullName));
528                                         }
529                                 }
530                         }
531                         else
532                         {
533                                 for (int i = length - 1; i >= 0; i--) 
534                                 {
535                                         Object srcval = source.GetValueImpl (source_pos + i);
536
537                                         try {
538                                                 dest.SetValueImpl (srcval, dest_pos + i);
539                                         } catch {
540                                                 if ((dst_type.IsValueType || dst_type.Equals (typeof (String))) &&
541                                                         (src_type.Equals (typeof (Object))))
542                                                         throw new InvalidCastException ();
543                                                 else
544                                                         throw new ArrayTypeMismatchException (
545                                                                 String.Format ("(Types: source={0};  target={1})", src_type.FullName, dst_type.FullName));
546                                         }
547                                 }
548                         }
549                 }
550                 
551                 public static int IndexOf (Array array, object value)
552                 {
553                         if (array == null)
554                                 throw new ArgumentNullException ();
555         
556                         return IndexOf (array, value, 0, array.Length);
557                 }
558
559                 public static int IndexOf (Array array, object value, int index)
560                 {
561                         if (array == null)
562                                 throw new ArgumentNullException ();
563
564                         return IndexOf (array, value, index, array.Length - index);
565                 }
566                 
567                 public static int IndexOf (Array array, object value, int index, int length)
568                 {
569                         if (array == null)
570                                 throw new ArgumentNullException ();
571         
572                         if (array.Rank > 1)
573                                 throw new RankException ();
574
575                         if (length < 0 || index < array.GetLowerBound (0) ||
576                             index+length-1 > array.GetUpperBound (0))
577                                 throw new ArgumentOutOfRangeException ();
578
579                         for (int i = 0; i < length; i++)
580                         {
581                                 if (array.GetValueImpl(index + i).Equals(value))
582                                         return index + i;
583                         }
584
585                         return array.GetLowerBound (0) - 1;
586                 }
587
588                 public static int LastIndexOf (Array array, object value)
589                 {
590                         if (array == null)
591                                 throw new ArgumentNullException ();
592         
593                         return LastIndexOf (array, value, array.Length-1);
594                 }
595
596                 public static int LastIndexOf (Array array, object value, int index)
597                 {
598                         if (array == null)
599                                 throw new ArgumentNullException ();
600         
601                         return LastIndexOf (array, value, index, index-array.GetLowerBound(0)+1);
602                 }
603                 
604                 public static int LastIndexOf (Array array, object value, int index, int length)
605                 {
606                         if (array == null)
607                                 throw new ArgumentNullException ();
608         
609                         if (array.Rank > 1)
610                                 throw new RankException ();
611
612                         if (length < 0 || index-length+1 < array.GetLowerBound (0) ||
613                             index > array.GetUpperBound (0))
614                                 throw new ArgumentOutOfRangeException ();
615
616                         for (int i = index; i >= index-length+1; i--)
617                         {
618                                 if (array.GetValueImpl(i).Equals(value))
619                                         return i;
620                         }
621
622                         return array.GetLowerBound (0) - 1;
623                 }
624
625                 public static void Reverse (Array array)
626                 {
627                         if (array == null)
628                                 throw new ArgumentNullException ();
629
630                         Reverse (array, array.GetLowerBound (0), array.GetLength (0));
631                 }
632
633                 public static void Reverse (Array array, int index, int length)
634                 {
635                         if (array == null)
636                                 throw new ArgumentNullException ();
637
638                         if (array.Rank > 1)
639                                 throw new RankException ();
640
641                         if (index < array.GetLowerBound (0) || length < 0)
642                                 throw new ArgumentOutOfRangeException ();
643
644                         if (index + length > array.GetUpperBound (0) + 1)
645                                 throw new ArgumentException ();
646
647                         for (int i = 0; i < length/2; i++)
648                         {
649                                 object tmp;
650
651                                 tmp = array.GetValueImpl (index + i);
652                                 array.SetValueImpl(array.GetValueImpl (index + length - i - 1), index + i);
653                                 array.SetValueImpl(tmp, index + length - i - 1);
654                         }
655                 }               
656                 
657                 public static void Sort (Array array)
658                 {
659                         if (array == null)
660                                 throw new ArgumentNullException ();
661
662                         Sort (array, null, array.GetLowerBound (0), array.GetLength (0), null);
663                 }
664
665                 public static void Sort (Array keys, Array items)
666                 {
667                         if (keys == null)
668                                 throw new ArgumentNullException ();
669
670                         Sort (keys, items, keys.GetLowerBound (0), keys.GetLength (0), null);
671                 }
672
673                 public static void Sort (Array array, IComparer comparer)
674                 {
675                         if (array == null)
676                                 throw new ArgumentNullException ();
677
678                         Sort (array, null, array.GetLowerBound (0), array.GetLength (0), comparer);
679                 }
680
681                 public static void Sort (Array array, int index, int length)
682                 {
683                         Sort (array, null, index, length, null);
684                 }
685
686                 public static void Sort (Array keys, Array items, IComparer comparer)
687                 {
688                         if (keys == null)
689                                 throw new ArgumentNullException ();
690
691                         Sort (keys, items, keys.GetLowerBound (0), keys.GetLength (0), comparer);
692                 }
693
694                 public static void Sort (Array keys, Array items, int index, int length)
695                 {
696                         Sort (keys, items, index, length, null);
697                 }
698
699                 public static void Sort (Array array, int index, int length, IComparer comparer)
700                 {
701                         Sort (array, null, index, length, comparer);
702                 }
703
704                 public static void Sort (Array keys, Array items, int index, int length, IComparer comparer)
705                 {
706                         int low0 = index;
707                         int high0 = index + length - 1;
708
709                         qsort (keys, items, index, index + length - 1, comparer);
710                 }
711
712                 private static void qsort (Array keys, Array items, int low0, int high0, IComparer comparer)
713                 {
714                         if (keys == null)
715                                 throw new ArgumentNullException ();
716
717                         if (keys.Rank > 1 || (items != null && items.Rank > 1))
718                                 throw new RankException ();
719
720                         if (low0 >= high0)
721                                 return;
722
723                         int low = low0;
724                         int high = high0;
725
726                         object objPivot = keys.GetValueImpl ((low + high) / 2);
727
728                         while (low <= high)
729                         {
730                                 // Move the walls in
731                                 while (low < high0 && compare (keys.GetValueImpl (low), objPivot, comparer) < 0)
732                                         ++low;
733                                 while (high > low0 && compare (objPivot, keys.GetValueImpl (high), comparer) < 0)
734                                         --high;
735
736                                 if (low <= high)
737                                 {
738                                         swap (keys, items, low, high);
739                                         ++low;
740                                         --high;
741                                 }
742                         }
743
744                         if (low0 < high)
745                                 qsort (keys, items, low0, high, comparer);
746                         if (low < high0)
747                                 qsort (keys, items, low, high0, comparer);
748                 }
749
750                 private static void swap (Array keys, Array items, int i, int j)
751                 {
752                         object tmp;
753
754                         tmp = keys.GetValueImpl (i);
755                         keys.SetValueImpl (keys.GetValue (j), i);
756                         keys.SetValueImpl (tmp, j);
757
758                         if (items != null)
759                         {
760                                 tmp = items.GetValueImpl (i);
761                                 items.SetValueImpl (items.GetValueImpl (j), i);
762                                 items.SetValueImpl (tmp, j);
763                         }
764                 }
765
766                 private static int compare (object value1, object value2, IComparer comparer)
767                 {
768                         if (comparer == null)
769                                 return ((IComparable) value1).CompareTo(value2);
770                         else
771                                 return comparer.Compare(value1, value2);
772                 }
773         
774                 public virtual void CopyTo (Array array, int index)
775                 {
776                         if (array == null)
777                                 throw new ArgumentNullException ();
778
779                         // The order of these exception checks may look strange,
780                         // but that's how the microsoft runtime does it.
781                         if (this.Rank > 1)
782                                 throw new RankException ();
783                         if (index + this.GetLength (0) > array.GetLowerBound (0) + array.GetLength (0))
784                                 throw new ArgumentException ();
785                         if (array.Rank > 1)
786                                 throw new RankException ();
787                         if (index < 0)
788                                 throw new ArgumentOutOfRangeException ();
789
790                         Copy (this, this.GetLowerBound(0), array, index, this.GetLength (0));
791                 }
792
793                 internal class SimpleEnumerator : IEnumerator {
794                         Array enumeratee;
795                         int currentpos;
796                         int length;
797
798                         public SimpleEnumerator (Array arrayToEnumerate) {
799                                 this.enumeratee = arrayToEnumerate;
800                                 this.currentpos = -1;
801                                 this.length = arrayToEnumerate.Length;
802                         }
803
804                         public object Current {
805                                 get {
806                                         // Exception messages based on MS implementation
807                                         if (currentpos < 0 ) {
808                                                 throw new InvalidOperationException
809                                                         ("Enumeration has not started");
810                                         }
811                                         if  (currentpos >= length) {
812                                                 throw new InvalidOperationException
813                                                         ("Enumeration has already ended");
814                                         }
815                                         // Current should not increase the position. So no ++ over here.
816                                         return enumeratee.GetValueImpl(currentpos);
817                                 }
818                         }
819
820                         public bool MoveNext() {
821                                 //The docs say Current should throw an exception if last
822                                 //call to MoveNext returned false. This means currentpos
823                                 //should be set to length when returning false.
824                                         if (currentpos < length) {
825                                                 currentpos++;
826                                         }
827                                 if(currentpos < length)
828                                         return true;
829                                 else
830                                         return false;
831                         }
832
833                         public void Reset() {
834                                 currentpos= -1;
835                         }
836                 }
837         }
838 }