1
#region Copyright & License
3
// Copyright 2001-2005 The Apache Software Foundation
5
// Licensed under the Apache License, Version 2.0 (the "License");
6
// you may not use this file except in compliance with the License.
7
// You may obtain a copy of the License at
9
// http://www.apache.org/licenses/LICENSE-2.0
11
// Unless required by applicable law or agreed to in writing, software
12
// distributed under the License is distributed on an "AS IS" BASIS,
13
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
// See the License for the specific language governing permissions and
15
// limitations under the License.
20
using System.Collections;
22
namespace log4net.Appender
25
/// A strongly-typed collection of <see cref="IAppender"/> objects.
27
/// <author>Nicko Cadell</author>
28
public class AppenderCollection : ICollection, IList, IEnumerable, ICloneable
32
/// Supports type-safe iteration over a <see cref="AppenderCollection"/>.
35
public interface IAppenderCollectionEnumerator
38
/// Gets the current element in the collection.
40
IAppender Current { get; }
43
/// Advances the enumerator to the next element in the collection.
46
/// <c>true</c> if the enumerator was successfully advanced to the next element;
47
/// <c>false</c> if the enumerator has passed the end of the collection.
49
/// <exception cref="InvalidOperationException">
50
/// The collection was modified after the enumerator was created.
55
/// Sets the enumerator to its initial position, before the first element in the collection.
61
private const int DEFAULT_CAPACITY = 16;
63
#region Implementation (data)
65
private IAppender[] m_array;
66
private int m_count = 0;
67
private int m_version = 0;
71
#region Static Wrappers
74
/// Creates a read-only wrapper for a <c>AppenderCollection</c> instance.
76
/// <param name="list">list to create a readonly wrapper arround</param>
78
/// An <c>AppenderCollection</c> wrapper that is read-only.
80
public static AppenderCollection ReadOnly(AppenderCollection list)
82
if(list==null) throw new ArgumentNullException("list");
84
return new ReadOnlyAppenderCollection(list);
92
/// An empty readonly static AppenderCollection
94
public static readonly AppenderCollection EmptyCollection = ReadOnly(new AppenderCollection(0));
101
/// Initializes a new instance of the <c>AppenderCollection</c> class
102
/// that is empty and has the default initial capacity.
104
public AppenderCollection()
106
m_array = new IAppender[DEFAULT_CAPACITY];
110
/// Initializes a new instance of the <c>AppenderCollection</c> class
111
/// that has the specified initial capacity.
113
/// <param name="capacity">
114
/// The number of elements that the new <c>AppenderCollection</c> is initially capable of storing.
116
public AppenderCollection(int capacity)
118
m_array = new IAppender[capacity];
122
/// Initializes a new instance of the <c>AppenderCollection</c> class
123
/// that contains elements copied from the specified <c>AppenderCollection</c>.
125
/// <param name="c">The <c>AppenderCollection</c> whose elements are copied to the new collection.</param>
126
public AppenderCollection(AppenderCollection c)
128
m_array = new IAppender[c.Count];
133
/// Initializes a new instance of the <c>AppenderCollection</c> class
134
/// that contains elements copied from the specified <see cref="IAppender"/> array.
136
/// <param name="a">The <see cref="IAppender"/> array whose elements are copied to the new list.</param>
137
public AppenderCollection(IAppender[] a)
139
m_array = new IAppender[a.Length];
144
/// Initializes a new instance of the <c>AppenderCollection</c> class
145
/// that contains elements copied from the specified <see cref="IAppender"/> collection.
147
/// <param name="col">The <see cref="IAppender"/> collection whose elements are copied to the new list.</param>
148
public AppenderCollection(ICollection col)
150
m_array = new IAppender[col.Count];
155
/// Type visible only to our subclasses
156
/// Used to access protected constructor
159
internal protected enum Tag
168
/// Allow subclasses to avoid our default constructors
170
/// <param name="tag"></param>
172
internal protected AppenderCollection(Tag tag)
179
#region Operations (type-safe ICollection)
182
/// Gets the number of elements actually contained in the <c>AppenderCollection</c>.
184
public virtual int Count
186
get { return m_count; }
190
/// Copies the entire <c>AppenderCollection</c> to a one-dimensional
191
/// <see cref="IAppender"/> array.
193
/// <param name="array">The one-dimensional <see cref="IAppender"/> array to copy to.</param>
194
public virtual void CopyTo(IAppender[] array)
196
this.CopyTo(array, 0);
200
/// Copies the entire <c>AppenderCollection</c> to a one-dimensional
201
/// <see cref="IAppender"/> array, starting at the specified index of the target array.
203
/// <param name="array">The one-dimensional <see cref="IAppender"/> array to copy to.</param>
204
/// <param name="start">The zero-based index in <paramref name="array"/> at which copying begins.</param>
205
public virtual void CopyTo(IAppender[] array, int start)
207
if (m_count > array.GetUpperBound(0) + 1 - start)
209
throw new System.ArgumentException("Destination array was not long enough.");
212
Array.Copy(m_array, 0, array, start, m_count);
216
/// Gets a value indicating whether access to the collection is synchronized (thread-safe).
218
/// <returns>true if access to the ICollection is synchronized (thread-safe); otherwise, false.</returns>
219
public virtual bool IsSynchronized
221
get { return m_array.IsSynchronized; }
225
/// Gets an object that can be used to synchronize access to the collection.
227
public virtual object SyncRoot
229
get { return m_array.SyncRoot; }
234
#region Operations (type-safe IList)
237
/// Gets or sets the <see cref="IAppender"/> at the specified index.
239
/// <param name="index">The zero-based index of the element to get or set.</param>
240
/// <exception cref="ArgumentOutOfRangeException">
241
/// <para><paramref name="index"/> is less than zero</para>
242
/// <para>-or-</para>
243
/// <para><paramref name="index"/> is equal to or greater than <see cref="AppenderCollection.Count"/>.</para>
245
public virtual IAppender this[int index]
249
ValidateIndex(index); // throws
250
return m_array[index];
254
ValidateIndex(index); // throws
256
m_array[index] = value;
261
/// Adds a <see cref="IAppender"/> to the end of the <c>AppenderCollection</c>.
263
/// <param name="item">The <see cref="IAppender"/> to be added to the end of the <c>AppenderCollection</c>.</param>
264
/// <returns>The index at which the value has been added.</returns>
265
public virtual int Add(IAppender item)
267
if (m_count == m_array.Length)
269
EnsureCapacity(m_count + 1);
272
m_array[m_count] = item;
279
/// Removes all elements from the <c>AppenderCollection</c>.
281
public virtual void Clear()
284
m_array = new IAppender[DEFAULT_CAPACITY];
289
/// Creates a shallow copy of the <see cref="AppenderCollection"/>.
291
/// <returns>A new <see cref="AppenderCollection"/> with a shallow copy of the collection data.</returns>
292
public virtual object Clone()
294
AppenderCollection newCol = new AppenderCollection(m_count);
295
Array.Copy(m_array, 0, newCol.m_array, 0, m_count);
296
newCol.m_count = m_count;
297
newCol.m_version = m_version;
303
/// Determines whether a given <see cref="IAppender"/> is in the <c>AppenderCollection</c>.
305
/// <param name="item">The <see cref="IAppender"/> to check for.</param>
306
/// <returns><c>true</c> if <paramref name="item"/> is found in the <c>AppenderCollection</c>; otherwise, <c>false</c>.</returns>
307
public virtual bool Contains(IAppender item)
309
for (int i=0; i != m_count; ++i)
311
if (m_array[i].Equals(item))
320
/// Returns the zero-based index of the first occurrence of a <see cref="IAppender"/>
321
/// in the <c>AppenderCollection</c>.
323
/// <param name="item">The <see cref="IAppender"/> to locate in the <c>AppenderCollection</c>.</param>
325
/// The zero-based index of the first occurrence of <paramref name="item"/>
326
/// in the entire <c>AppenderCollection</c>, if found; otherwise, -1.
328
public virtual int IndexOf(IAppender item)
330
for (int i=0; i != m_count; ++i)
332
if (m_array[i].Equals(item))
341
/// Inserts an element into the <c>AppenderCollection</c> at the specified index.
343
/// <param name="index">The zero-based index at which <paramref name="item"/> should be inserted.</param>
344
/// <param name="item">The <see cref="IAppender"/> to insert.</param>
345
/// <exception cref="ArgumentOutOfRangeException">
346
/// <para><paramref name="index"/> is less than zero</para>
347
/// <para>-or-</para>
348
/// <para><paramref name="index"/> is equal to or greater than <see cref="AppenderCollection.Count"/>.</para>
350
public virtual void Insert(int index, IAppender item)
352
ValidateIndex(index, true); // throws
354
if (m_count == m_array.Length)
356
EnsureCapacity(m_count + 1);
361
Array.Copy(m_array, index, m_array, index + 1, m_count - index);
364
m_array[index] = item;
370
/// Removes the first occurrence of a specific <see cref="IAppender"/> from the <c>AppenderCollection</c>.
372
/// <param name="item">The <see cref="IAppender"/> to remove from the <c>AppenderCollection</c>.</param>
373
/// <exception cref="ArgumentException">
374
/// The specified <see cref="IAppender"/> was not found in the <c>AppenderCollection</c>.
376
public virtual void Remove(IAppender item)
378
int i = IndexOf(item);
381
throw new System.ArgumentException("Cannot remove the specified item because it was not found in the specified Collection.");
389
/// Removes the element at the specified index of the <c>AppenderCollection</c>.
391
/// <param name="index">The zero-based index of the element to remove.</param>
392
/// <exception cref="ArgumentOutOfRangeException">
393
/// <para><paramref name="index"/> is less than zero</para>
394
/// <para>-or-</para>
395
/// <para><paramref name="index"/> is equal to or greater than <see cref="AppenderCollection.Count"/>.</para>
397
public virtual void RemoveAt(int index)
399
ValidateIndex(index); // throws
405
Array.Copy(m_array, index + 1, m_array, index, m_count - index);
408
// We can't set the deleted entry equal to null, because it might be a value type.
409
// Instead, we'll create an empty single-element array of the right type and copy it
410
// over the entry we want to erase.
411
IAppender[] temp = new IAppender[1];
412
Array.Copy(temp, 0, m_array, m_count, 1);
417
/// Gets a value indicating whether the collection has a fixed size.
419
/// <value>true if the collection has a fixed size; otherwise, false. The default is false</value>
420
public virtual bool IsFixedSize
422
get { return false; }
426
/// Gets a value indicating whether the IList is read-only.
428
/// <value>true if the collection is read-only; otherwise, false. The default is false</value>
429
public virtual bool IsReadOnly
431
get { return false; }
436
#region Operations (type-safe IEnumerable)
439
/// Returns an enumerator that can iterate through the <c>AppenderCollection</c>.
441
/// <returns>An <see cref="Enumerator"/> for the entire <c>AppenderCollection</c>.</returns>
442
public virtual IAppenderCollectionEnumerator GetEnumerator()
444
return new Enumerator(this);
449
#region Public helpers (just to mimic some nice features of ArrayList)
452
/// Gets or sets the number of elements the <c>AppenderCollection</c> can contain.
454
public virtual int Capacity
458
return m_array.Length;
467
if (value != m_array.Length)
471
IAppender[] temp = new IAppender[value];
472
Array.Copy(m_array, 0, temp, 0, m_count);
477
m_array = new IAppender[DEFAULT_CAPACITY];
484
/// Adds the elements of another <c>AppenderCollection</c> to the current <c>AppenderCollection</c>.
486
/// <param name="x">The <c>AppenderCollection</c> whose elements should be added to the end of the current <c>AppenderCollection</c>.</param>
487
/// <returns>The new <see cref="AppenderCollection.Count"/> of the <c>AppenderCollection</c>.</returns>
488
public virtual int AddRange(AppenderCollection x)
490
if (m_count + x.Count >= m_array.Length)
492
EnsureCapacity(m_count + x.Count);
495
Array.Copy(x.m_array, 0, m_array, m_count, x.Count);
503
/// Adds the elements of a <see cref="IAppender"/> array to the current <c>AppenderCollection</c>.
505
/// <param name="x">The <see cref="IAppender"/> array whose elements should be added to the end of the <c>AppenderCollection</c>.</param>
506
/// <returns>The new <see cref="AppenderCollection.Count"/> of the <c>AppenderCollection</c>.</returns>
507
public virtual int AddRange(IAppender[] x)
509
if (m_count + x.Length >= m_array.Length)
511
EnsureCapacity(m_count + x.Length);
514
Array.Copy(x, 0, m_array, m_count, x.Length);
522
/// Adds the elements of a <see cref="IAppender"/> collection to the current <c>AppenderCollection</c>.
524
/// <param name="col">The <see cref="IAppender"/> collection whose elements should be added to the end of the <c>AppenderCollection</c>.</param>
525
/// <returns>The new <see cref="AppenderCollection.Count"/> of the <c>AppenderCollection</c>.</returns>
526
public virtual int AddRange(ICollection col)
528
if (m_count + col.Count >= m_array.Length)
530
EnsureCapacity(m_count + col.Count);
533
foreach(object item in col)
535
Add((IAppender)item);
542
/// Sets the capacity to the actual number of elements.
544
public virtual void TrimToSize()
546
this.Capacity = m_count;
550
/// Return the collection elements as an array
552
/// <returns>the array</returns>
553
public virtual IAppender[] ToArray()
555
IAppender[] resultArray = new IAppender[m_count];
558
Array.Copy(m_array, 0, resultArray, 0, m_count);
565
#region Implementation (helpers)
567
/// <exception cref="ArgumentOutOfRangeException">
568
/// <para><paramref name="index"/> is less than zero</para>
569
/// <para>-or-</para>
570
/// <para><paramref name="index"/> is equal to or greater than <see cref="AppenderCollection.Count"/>.</para>
572
private void ValidateIndex(int i)
574
ValidateIndex(i, false);
577
/// <exception cref="ArgumentOutOfRangeException">
578
/// <para><paramref name="index"/> is less than zero</para>
579
/// <para>-or-</para>
580
/// <para><paramref name="index"/> is equal to or greater than <see cref="AppenderCollection.Count"/>.</para>
582
private void ValidateIndex(int i, bool allowEqualEnd)
584
int max = (allowEqualEnd) ? (m_count) : (m_count-1);
585
if (i < 0 || i > max)
587
throw log4net.Util.SystemInfo.CreateArgumentOutOfRangeException("i", (object)i, "Index was out of range. Must be non-negative and less than the size of the collection. [" + (object)i + "] Specified argument was out of the range of valid values.");
591
private void EnsureCapacity(int min)
593
int newCapacity = ((m_array.Length == 0) ? DEFAULT_CAPACITY : m_array.Length * 2);
594
if (newCapacity < min)
599
this.Capacity = newCapacity;
604
#region Implementation (ICollection)
606
void ICollection.CopyTo(Array array, int start)
610
Array.Copy(m_array, 0, array, start, m_count);
616
#region Implementation (IList)
618
object IList.this[int i]
620
get { return (object)this[i]; }
621
set { this[i] = (IAppender)value; }
624
int IList.Add(object x)
626
return this.Add((IAppender)x);
629
bool IList.Contains(object x)
631
return this.Contains((IAppender)x);
634
int IList.IndexOf(object x)
636
return this.IndexOf((IAppender)x);
639
void IList.Insert(int pos, object x)
641
this.Insert(pos, (IAppender)x);
644
void IList.Remove(object x)
646
this.Remove((IAppender)x);
649
void IList.RemoveAt(int pos)
656
#region Implementation (IEnumerable)
658
IEnumerator IEnumerable.GetEnumerator()
660
return (IEnumerator)(this.GetEnumerator());
665
#region Nested enumerator class
668
/// Supports simple iteration over a <see cref="AppenderCollection"/>.
671
private sealed class Enumerator : IEnumerator, IAppenderCollectionEnumerator
673
#region Implementation (data)
675
private readonly AppenderCollection m_collection;
677
private int m_version;
684
/// Initializes a new instance of the <c>Enumerator</c> class.
686
/// <param name="tc"></param>
687
internal Enumerator(AppenderCollection tc)
691
m_version = tc.m_version;
696
#region Operations (type-safe IEnumerator)
699
/// Gets the current element in the collection.
701
public IAppender Current
703
get { return m_collection[m_index]; }
707
/// Advances the enumerator to the next element in the collection.
710
/// <c>true</c> if the enumerator was successfully advanced to the next element;
711
/// <c>false</c> if the enumerator has passed the end of the collection.
713
/// <exception cref="InvalidOperationException">
714
/// The collection was modified after the enumerator was created.
716
public bool MoveNext()
718
if (m_version != m_collection.m_version)
720
throw new System.InvalidOperationException("Collection was modified; enumeration operation may not execute.");
724
return (m_index < m_collection.Count);
728
/// Sets the enumerator to its initial position, before the first element in the collection.
736
#region Implementation (IEnumerator)
738
object IEnumerator.Current
740
get { return this.Current; }
748
#region Nested Read Only Wrapper class
751
private sealed class ReadOnlyAppenderCollection : AppenderCollection, ICollection
753
#region Implementation (data)
755
private readonly AppenderCollection m_collection;
761
internal ReadOnlyAppenderCollection(AppenderCollection list) : base(Tag.Default)
768
#region Type-safe ICollection
770
public override void CopyTo(IAppender[] array)
772
m_collection.CopyTo(array);
775
public override void CopyTo(IAppender[] array, int start)
777
m_collection.CopyTo(array,start);
780
void ICollection.CopyTo(Array array, int start)
782
((ICollection)m_collection).CopyTo(array, start);
785
public override int Count
787
get { return m_collection.Count; }
790
public override bool IsSynchronized
792
get { return m_collection.IsSynchronized; }
795
public override object SyncRoot
797
get { return this.m_collection.SyncRoot; }
802
#region Type-safe IList
804
public override IAppender this[int i]
806
get { return m_collection[i]; }
807
set { throw new NotSupportedException("This is a Read Only Collection and can not be modified"); }
810
public override int Add(IAppender x)
812
throw new NotSupportedException("This is a Read Only Collection and can not be modified");
815
public override void Clear()
817
throw new NotSupportedException("This is a Read Only Collection and can not be modified");
820
public override bool Contains(IAppender x)
822
return m_collection.Contains(x);
825
public override int IndexOf(IAppender x)
827
return m_collection.IndexOf(x);
830
public override void Insert(int pos, IAppender x)
832
throw new NotSupportedException("This is a Read Only Collection and can not be modified");
835
public override void Remove(IAppender x)
837
throw new NotSupportedException("This is a Read Only Collection and can not be modified");
840
public override void RemoveAt(int pos)
842
throw new NotSupportedException("This is a Read Only Collection and can not be modified");
845
public override bool IsFixedSize
850
public override bool IsReadOnly
857
#region Type-safe IEnumerable
859
public override IAppenderCollectionEnumerator GetEnumerator()
861
return m_collection.GetEnumerator();
866
#region Public Helpers
868
// (just to mimic some nice features of ArrayList)
869
public override int Capacity
871
get { return m_collection.Capacity; }
872
set { throw new NotSupportedException("This is a Read Only Collection and can not be modified"); }
875
public override int AddRange(AppenderCollection x)
877
throw new NotSupportedException("This is a Read Only Collection and can not be modified");
880
public override int AddRange(IAppender[] x)
882
throw new NotSupportedException("This is a Read Only Collection and can not be modified");