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 return Find (value) != null;
194 public void CopyTo (T [] array, int index)
197 throw new ArgumentNullException ("array");
198 if ( (uint) index < (uint) array.GetLowerBound (0))
199 throw new ArgumentOutOfRangeException ("index");
201 throw new ArgumentException ("array", "Array is multidimensional");
202 if (array.Length - index + array.GetLowerBound (0) < count)
203 throw new ArgumentException ("number of items exceeds capacity");
205 LinkedListNode <T> node = first;
210 array [index] = node.Value;
214 while (node != first);
217 public LinkedListNode<T> Find (T value)
225 if (node.Value == null)
228 if (EqualityComparer<T>.Default.Equals (node.Value, value))
233 } while (node != first);
238 public LinkedListNode<T> FindLast (T value)
248 if (node.Value == null)
251 if (EqualityComparer<T>.Default.Equals (node.Value, value))
254 } while (node != first);
259 public Enumerator GetEnumerator ()
261 return new Enumerator (this);
264 [SecurityPermission (SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter)]
265 public virtual void GetObjectData (SerializationInfo info, StreamingContext context)
267 T [] data = new T [count];
269 info.AddValue (DataArrayKey, data, typeof (T []));
270 info.AddValue (VersionKey, version);
273 public virtual void OnDeserialization (object sender)
277 T [] data = (T []) si.GetValue (DataArrayKey, typeof (T []));
279 foreach (T item in data)
281 version = si.GetUInt32 (VersionKey);
286 public bool Remove (T value)
288 LinkedListNode <T> node = Find (value);
295 public void Remove (LinkedListNode <T> node)
297 VerifyReferencedNode (node);
303 first = first.forward;
309 public void RemoveFirst ()
312 throw new InvalidOperationException ();
317 public void RemoveLast ()
320 throw new InvalidOperationException ();
325 void ICollection <T>.Add (T value)
330 void ICollection.CopyTo (Array array, int index)
332 T [] Tarray = array as T [];
334 throw new ArgumentException ("array");
335 CopyTo (Tarray, index);
338 IEnumerator <T> IEnumerable <T>.GetEnumerator ()
340 return GetEnumerator ();
343 IEnumerator IEnumerable.GetEnumerator ()
345 return GetEnumerator ();
349 get { return (int) count; }
352 public LinkedListNode <T> First {
353 get { return first; }
356 public LinkedListNode <T> Last {
357 get { return (first != null) ? first.back : null; }
360 bool ICollection <T>.IsReadOnly {
361 get { return false; }
364 bool ICollection.IsSynchronized {
365 get { return false; }
368 object ICollection.SyncRoot {
372 [Serializable, StructLayout (LayoutKind.Sequential)]
373 public struct Enumerator : IEnumerator <T>, IDisposable, IEnumerator
375 , ISerializable, IDeserializationCallback
378 const String VersionKey = "version";
379 const String IndexKey = "index";
380 const String ListKey = "list";
383 LinkedListNode <T> current;
387 SerializationInfo si;
389 internal Enumerator (SerializationInfo info, StreamingContext context)
392 list = (LinkedList <T>) si.GetValue (ListKey, typeof (LinkedList <T>));
393 index = si.GetInt32 (IndexKey);
394 version = si.GetUInt32 (VersionKey);
399 internal Enumerator (LinkedList <T> parent)
407 version = parent.version;
413 throw new ObjectDisposedException (null);
415 throw new InvalidOperationException ();
416 return current.Value;
420 object IEnumerator.Current {
421 get { return Current; }
424 public bool MoveNext ()
427 throw new ObjectDisposedException (null);
428 if (version != list.version)
429 throw new InvalidOperationException ("list modified");
431 if (current == null) {
433 current = list.first;
435 current = current.forward;
436 if (current == list.first)
440 if (current == null) {
441 index = int.MaxValue;
449 void IEnumerator.Reset ()
452 throw new ObjectDisposedException (null);
453 if (version != list.version)
454 throw new InvalidOperationException ("list modified");
460 public void Dispose ()
463 throw new ObjectDisposedException (null);
469 [SecurityPermission (SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter)]
470 void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context)
473 throw new ObjectDisposedException (null);
474 info.AddValue (VersionKey, version);
475 info.AddValue (IndexKey, index);
478 void IDeserializationCallback.OnDeserialization (object sender)
484 ( (IDeserializationCallback) list).OnDeserialization (this);
488 if (version == list.version && index != -1)
490 LinkedListNode <T> node = list.First;
492 for (int i = 0; i < index; i++)