2 // System.Collections.Generic.LinkedList
7 // (C) 2005 David Waite (mass@akuma.org)
11 // Copyright (C) 2005 David Waite
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:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
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.
34 using System.Runtime.InteropServices;
35 using System.Runtime.Serialization;
36 using System.Security.Permissions;
37 using System.Diagnostics;
39 namespace System.Collections.Generic
41 [Serializable, ComVisible (false)]
42 [DebuggerDisplay ("Count={Count}")]
43 [DebuggerTypeProxy (typeof (CollectionDebuggerView<>))]
44 public class LinkedList <T> : ICollection <T>, ICollection, ISerializable, IDeserializationCallback
46 const string DataArrayKey = "DataArray";
47 const string VersionKey = "version";
50 // Internally a circular list - first.back == last
51 internal LinkedListNode <T> first;
52 internal SerializationInfo si;
58 public LinkedList (IEnumerable <T> collection)
60 foreach (T item in collection)
64 protected LinkedList (SerializationInfo info, StreamingContext context)
69 void VerifyReferencedNode (LinkedListNode <T> node)
72 throw new ArgumentNullException ("node");
74 if (node.List != this)
75 throw new InvalidOperationException ();
78 static void VerifyBlankNode (LinkedListNode <T> newNode)
81 throw new ArgumentNullException ("newNode");
83 if (newNode.List != null)
84 throw new InvalidOperationException ();
87 public LinkedListNode <T> AddAfter (LinkedListNode <T> node, T value)
89 VerifyReferencedNode (node);
90 LinkedListNode <T> newNode = new LinkedListNode <T> (this, value, node, node.forward);
96 public void AddAfter (LinkedListNode <T> node, LinkedListNode <T> newNode)
98 VerifyReferencedNode (node);
99 VerifyBlankNode (newNode);
100 newNode.InsertBetween (node, node.forward, this);
105 public LinkedListNode <T> AddBefore (LinkedListNode <T> node, T value)
107 VerifyReferencedNode (node);
108 LinkedListNode <T> newNode = new LinkedListNode <T> (this, value, node.back, node);
117 public void AddBefore (LinkedListNode <T> node, LinkedListNode <T> newNode)
119 VerifyReferencedNode (node);
120 VerifyBlankNode (newNode);
121 newNode.InsertBetween (node.back, node, this);
129 public void AddFirst (LinkedListNode <T> node)
131 VerifyBlankNode (node);
133 node.SelfReference (this);
135 node.InsertBetween (first.back, first, this);
141 public LinkedListNode <T> AddFirst (T value)
143 LinkedListNode <T> newNode;
145 newNode = new LinkedListNode <T> (this, value);
147 newNode = new LinkedListNode <T> (this, value, first.back, first);
154 public LinkedListNode <T> AddLast (T value)
156 LinkedListNode <T> newNode;
159 newNode = new LinkedListNode <T> (this, value);
163 newNode = new LinkedListNode <T> (this, value, first.back, first);
169 public void AddLast (LinkedListNode <T> node)
171 VerifyBlankNode (node);
174 node.SelfReference (this);
178 node.InsertBetween (first.back, first, this);
185 while (first != null)
189 public bool Contains (T value)
191 LinkedListNode <T> node = first;
196 if (value.Equals (node.Value))
200 while (node != first);
205 public void CopyTo (T [] array, int index)
208 throw new ArgumentNullException ("array");
209 if ( (uint) index < (uint) array.GetLowerBound (0))
210 throw new ArgumentOutOfRangeException ("index");
212 throw new ArgumentException ("array", "Array is multidimensional");
213 if (array.Length - index + array.GetLowerBound (0) < count)
214 throw new ArgumentException ("number of items exceeds capacity");
216 LinkedListNode <T> node = first;
221 array [index] = node.Value;
225 while (node != first);
228 public LinkedListNode <T> Find (T value)
230 LinkedListNode <T> node = first;
235 if ( (value == null && node.Value == null) ||
236 (value != null && value.Equals (node.Value)) )
240 while (node != first);
245 public LinkedListNode <T> FindLast (T value)
247 LinkedListNode <T> node = first;
253 if (value.Equals (node.Value))
256 while (node != first);
261 public Enumerator GetEnumerator ()
263 return new Enumerator (this);
266 [SecurityPermission (SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter)]
267 public virtual void GetObjectData (SerializationInfo info, StreamingContext context)
269 T [] data = new T [count];
271 info.AddValue (DataArrayKey, data, typeof (T []));
272 info.AddValue (VersionKey, version);
275 public virtual void OnDeserialization (object sender)
279 T [] data = (T []) si.GetValue (DataArrayKey, typeof (T []));
281 foreach (T item in data)
283 version = si.GetUInt32 (VersionKey);
288 public bool Remove (T value)
290 LinkedListNode <T> node = Find (value);
297 public void Remove (LinkedListNode <T> node)
299 VerifyReferencedNode (node);
305 first = first.forward;
311 public void RemoveFirst ()
317 public void RemoveLast ()
323 void ICollection <T>.Add (T value)
328 void ICollection.CopyTo (Array array, int index)
330 T [] Tarray = array as T [];
332 throw new ArgumentException ("array");
333 CopyTo (Tarray, index);
336 IEnumerator <T> IEnumerable <T>.GetEnumerator ()
338 return GetEnumerator ();
341 IEnumerator IEnumerable.GetEnumerator ()
343 return GetEnumerator ();
347 get { return (int) count; }
350 public LinkedListNode <T> First {
351 get { return first; }
354 public LinkedListNode <T> Last {
355 get { return (first != null) ? first.back : null; }
358 bool ICollection <T>.IsReadOnly {
359 get { return false; }
362 bool ICollection.IsSynchronized {
363 get { return false; }
366 object ICollection.SyncRoot {
370 [Serializable, StructLayout (LayoutKind.Sequential)]
371 public struct Enumerator : IEnumerator <T>, IDisposable, IEnumerator
373 , ISerializable, IDeserializationCallback
376 const String VersionKey = "version";
377 const String IndexKey = "index";
378 const String ListKey = "list";
381 LinkedListNode <T> current;
385 SerializationInfo si;
387 internal Enumerator (SerializationInfo info, StreamingContext context)
390 list = (LinkedList <T>) si.GetValue (ListKey, typeof (LinkedList <T>));
391 index = si.GetInt32 (IndexKey);
392 version = si.GetUInt32 (VersionKey);
397 internal Enumerator (LinkedList <T> parent)
405 version = parent.version;
411 throw new ObjectDisposedException (null);
413 throw new InvalidOperationException ();
414 return current.Value;
418 object IEnumerator.Current {
419 get { return Current; }
422 public bool MoveNext ()
425 throw new ObjectDisposedException (null);
426 if (version != list.version)
427 throw new InvalidOperationException ("list modified");
430 current = list.first;
433 current = current.forward;
434 if (current == list.first)
446 void IEnumerator.Reset ()
449 throw new ObjectDisposedException (null);
450 if (version != list.version)
451 throw new InvalidOperationException ("list modified");
457 public void Dispose ()
460 throw new ObjectDisposedException (null);
466 [SecurityPermission (SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter)]
467 void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context)
470 throw new ObjectDisposedException (null);
471 info.AddValue (VersionKey, version);
472 info.AddValue (IndexKey, index);
475 void IDeserializationCallback.OnDeserialization (object sender)
481 ( (IDeserializationCallback) list).OnDeserialization (this);
485 if (version == list.version && index != -1)
487 LinkedListNode <T> node = list.First;
489 for (int i = 0; i < index; i++)