PageRenderTime 51ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/mcs/class/corlib/System.Collections.Generic/List.cs

https://bitbucket.org/danipen/mono
C# | 826 lines | 653 code | 126 blank | 47 comment | 106 complexity | 588a51de3d8a09a0aaceb8f39e64b705 MD5 | raw file
Possible License(s): Unlicense, Apache-2.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
  1. //
  2. // System.Collections.Generic.List
  3. //
  4. // Authors:
  5. // Ben Maurer (bmaurer@ximian.com)
  6. // Martin Baulig (martin@ximian.com)
  7. // Carlos Alberto Cortez (calberto.cortez@gmail.com)
  8. // David Waite (mass@akuma.org)
  9. // Marek Safar (marek.safar@gmail.com)
  10. //
  11. // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
  12. // Copyright (C) 2005 David Waite
  13. // Copyright (C) 2011,2012 Xamarin, Inc (http://www.xamarin.com)
  14. //
  15. // Permission is hereby granted, free of charge, to any person obtaining
  16. // a copy of this software and associated documentation files (the
  17. // "Software"), to deal in the Software without restriction, including
  18. // without limitation the rights to use, copy, modify, merge, publish,
  19. // distribute, sublicense, and/or sell copies of the Software, and to
  20. // permit persons to whom the Software is furnished to do so, subject to
  21. // the following conditions:
  22. //
  23. // The above copyright notice and this permission notice shall be
  24. // included in all copies or substantial portions of the Software.
  25. //
  26. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  27. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  28. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  29. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  30. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  31. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  32. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  33. //
  34. using System.Collections.ObjectModel;
  35. using System.Runtime.InteropServices;
  36. using System.Diagnostics;
  37. using System.Runtime.CompilerServices;
  38. namespace System.Collections.Generic {
  39. [Serializable]
  40. [DebuggerDisplay ("Count={Count}")]
  41. [DebuggerTypeProxy (typeof (CollectionDebuggerView<>))]
  42. public class List<T> : IList<T>, IList
  43. #if NET_4_5
  44. , IReadOnlyList<T>
  45. #endif
  46. {
  47. T [] _items;
  48. int _size;
  49. int _version;
  50. const int DefaultCapacity = 4;
  51. public List ()
  52. {
  53. _items = EmptyArray<T>.Value;
  54. }
  55. public List (IEnumerable <T> collection)
  56. {
  57. if (collection == null)
  58. throw new ArgumentNullException ("collection");
  59. // initialize to needed size (if determinable)
  60. ICollection <T> c = collection as ICollection <T>;
  61. if (c == null) {
  62. _items = EmptyArray<T>.Value;;
  63. AddEnumerable (collection);
  64. } else {
  65. _size = c.Count;
  66. _items = new T [Math.Max (_size, DefaultCapacity)];
  67. c.CopyTo (_items, 0);
  68. }
  69. }
  70. public List (int capacity)
  71. {
  72. if (capacity < 0)
  73. throw new ArgumentOutOfRangeException ("capacity");
  74. _items = new T [capacity];
  75. }
  76. internal List (T [] data, int size)
  77. {
  78. _items = data;
  79. _size = size;
  80. }
  81. public void Add (T item)
  82. {
  83. // If we check to see if we need to grow before trying to grow
  84. // we can speed things up by 25%
  85. if (_size == _items.Length)
  86. GrowIfNeeded (1);
  87. _items [_size++] = item;
  88. _version++;
  89. }
  90. void GrowIfNeeded (int newCount)
  91. {
  92. int minimumSize = _size + newCount;
  93. if (minimumSize > _items.Length)
  94. Capacity = Math.Max (Math.Max (Capacity * 2, DefaultCapacity), minimumSize);
  95. }
  96. void CheckRange (int idx, int count)
  97. {
  98. if (idx < 0)
  99. throw new ArgumentOutOfRangeException ("index");
  100. if (count < 0)
  101. throw new ArgumentOutOfRangeException ("count");
  102. if ((uint) idx + (uint) count > (uint) _size)
  103. throw new ArgumentException ("index and count exceed length of list");
  104. }
  105. void AddCollection (ICollection <T> collection)
  106. {
  107. int collectionCount = collection.Count;
  108. if (collectionCount == 0)
  109. return;
  110. GrowIfNeeded (collectionCount);
  111. collection.CopyTo (_items, _size);
  112. _size += collectionCount;
  113. }
  114. void AddEnumerable (IEnumerable <T> enumerable)
  115. {
  116. foreach (T t in enumerable)
  117. {
  118. Add (t);
  119. }
  120. }
  121. public void AddRange (IEnumerable <T> collection)
  122. {
  123. if (collection == null)
  124. throw new ArgumentNullException ("collection");
  125. ICollection <T> c = collection as ICollection <T>;
  126. if (c != null)
  127. AddCollection (c);
  128. else
  129. AddEnumerable (collection);
  130. _version++;
  131. }
  132. public ReadOnlyCollection <T> AsReadOnly ()
  133. {
  134. return new ReadOnlyCollection <T> (this);
  135. }
  136. public int BinarySearch (T item)
  137. {
  138. return Array.BinarySearch <T> (_items, 0, _size, item);
  139. }
  140. public int BinarySearch (T item, IComparer <T> comparer)
  141. {
  142. return Array.BinarySearch <T> (_items, 0, _size, item, comparer);
  143. }
  144. public int BinarySearch (int index, int count, T item, IComparer <T> comparer)
  145. {
  146. CheckRange (index, count);
  147. return Array.BinarySearch <T> (_items, index, count, item, comparer);
  148. }
  149. public void Clear ()
  150. {
  151. Array.Clear (_items, 0, _items.Length);
  152. _size = 0;
  153. _version++;
  154. }
  155. public bool Contains (T item)
  156. {
  157. return Array.IndexOf<T>(_items, item, 0, _size) != -1;
  158. }
  159. public List <TOutput> ConvertAll <TOutput> (Converter <T, TOutput> converter)
  160. {
  161. if (converter == null)
  162. throw new ArgumentNullException ("converter");
  163. List <TOutput> u = new List <TOutput> (_size);
  164. for (int i = 0; i < _size; i++)
  165. u._items[i] = converter(_items[i]);
  166. u._size = _size;
  167. return u;
  168. }
  169. public void CopyTo (T [] array)
  170. {
  171. Array.Copy (_items, 0, array, 0, _size);
  172. }
  173. public void CopyTo (T [] array, int arrayIndex)
  174. {
  175. Array.Copy (_items, 0, array, arrayIndex, _size);
  176. }
  177. public void CopyTo (int index, T [] array, int arrayIndex, int count)
  178. {
  179. CheckRange (index, count);
  180. Array.Copy (_items, index, array, arrayIndex, count);
  181. }
  182. public bool Exists (Predicate <T> match)
  183. {
  184. CheckMatch(match);
  185. return GetIndex(0, _size, match) != -1;
  186. }
  187. public T Find (Predicate <T> match)
  188. {
  189. CheckMatch(match);
  190. int i = GetIndex(0, _size, match);
  191. return (i != -1) ? _items [i] : default (T);
  192. }
  193. static void CheckMatch (Predicate <T> match)
  194. {
  195. if (match == null)
  196. throw new ArgumentNullException ("match");
  197. }
  198. public List <T> FindAll (Predicate <T> match)
  199. {
  200. CheckMatch (match);
  201. if (this._size <= 0x10000) // <= 8 * 1024 * 8 (8k in stack)
  202. return this.FindAllStackBits (match);
  203. else
  204. return this.FindAllList (match);
  205. }
  206. private List <T> FindAllStackBits (Predicate <T> match)
  207. {
  208. unsafe
  209. {
  210. uint *bits = stackalloc uint [(this._size / 32) + 1];
  211. uint *ptr = bits;
  212. int found = 0;
  213. uint bitmask = 0x80000000;
  214. for (int i = 0; i < this._size; i++)
  215. {
  216. if (match (this._items [i]))
  217. {
  218. (*ptr) = (*ptr) | bitmask;
  219. found++;
  220. }
  221. bitmask = bitmask >> 1;
  222. if (bitmask == 0)
  223. {
  224. ptr++;
  225. bitmask = 0x80000000;
  226. }
  227. }
  228. T [] results = new T [found];
  229. bitmask = 0x80000000;
  230. ptr = bits;
  231. int j = 0;
  232. for (int i = 0; i < this._size && j < found; i++)
  233. {
  234. if (((*ptr) & bitmask) == bitmask)
  235. results [j++] = this._items [i];
  236. bitmask = bitmask >> 1;
  237. if (bitmask == 0)
  238. {
  239. ptr++;
  240. bitmask = 0x80000000;
  241. }
  242. }
  243. return new List <T> (results, found);
  244. }
  245. }
  246. private List <T> FindAllList (Predicate <T> match)
  247. {
  248. List <T> results = new List <T> ();
  249. for (int i = 0; i < this._size; i++)
  250. if (match (this._items [i]))
  251. results.Add (this._items [i]);
  252. return results;
  253. }
  254. public int FindIndex (Predicate <T> match)
  255. {
  256. CheckMatch (match);
  257. return GetIndex (0, _size, match);
  258. }
  259. public int FindIndex (int startIndex, Predicate <T> match)
  260. {
  261. CheckMatch (match);
  262. CheckIndex (startIndex);
  263. return GetIndex (startIndex, _size - startIndex, match);
  264. }
  265. public int FindIndex (int startIndex, int count, Predicate <T> match)
  266. {
  267. CheckMatch (match);
  268. CheckRange (startIndex, count);
  269. return GetIndex (startIndex, count, match);
  270. }
  271. int GetIndex (int startIndex, int count, Predicate <T> match)
  272. {
  273. int end = startIndex + count;
  274. for (int i = startIndex; i < end; i ++)
  275. if (match (_items [i]))
  276. return i;
  277. return -1;
  278. }
  279. public T FindLast (Predicate <T> match)
  280. {
  281. CheckMatch (match);
  282. int i = GetLastIndex (0, _size, match);
  283. return i == -1 ? default (T) : this [i];
  284. }
  285. public int FindLastIndex (Predicate <T> match)
  286. {
  287. CheckMatch (match);
  288. return GetLastIndex (0, _size, match);
  289. }
  290. public int FindLastIndex (int startIndex, Predicate <T> match)
  291. {
  292. CheckMatch (match);
  293. CheckIndex (startIndex);
  294. return GetLastIndex (0, startIndex + 1, match);
  295. }
  296. public int FindLastIndex (int startIndex, int count, Predicate <T> match)
  297. {
  298. CheckMatch (match);
  299. int start = startIndex - count + 1;
  300. CheckRange (start, count);
  301. return GetLastIndex (start, count, match);
  302. }
  303. int GetLastIndex (int startIndex, int count, Predicate <T> match)
  304. {
  305. // unlike FindLastIndex, takes regular params for search range
  306. for (int i = startIndex + count; i != startIndex;)
  307. if (match (_items [--i]))
  308. return i;
  309. return -1;
  310. }
  311. public void ForEach (Action <T> action)
  312. {
  313. if (action == null)
  314. throw new ArgumentNullException ("action");
  315. for(int i=0; i < _size; i++)
  316. action(_items[i]);
  317. }
  318. public Enumerator GetEnumerator ()
  319. {
  320. return new Enumerator (this);
  321. }
  322. public List <T> GetRange (int index, int count)
  323. {
  324. CheckRange (index, count);
  325. T [] tmpArray = new T [count];
  326. Array.Copy (_items, index, tmpArray, 0, count);
  327. return new List <T> (tmpArray, count);
  328. }
  329. public int IndexOf (T item)
  330. {
  331. return Array.IndexOf<T> (_items, item, 0, _size);
  332. }
  333. public int IndexOf (T item, int index)
  334. {
  335. CheckIndex (index);
  336. return Array.IndexOf<T> (_items, item, index, _size - index);
  337. }
  338. public int IndexOf (T item, int index, int count)
  339. {
  340. if (index < 0)
  341. throw new ArgumentOutOfRangeException ("index");
  342. if (count < 0)
  343. throw new ArgumentOutOfRangeException ("count");
  344. if ((uint) index + (uint) count > (uint) _size)
  345. throw new ArgumentOutOfRangeException ("index and count exceed length of list");
  346. return Array.IndexOf<T> (_items, item, index, count);
  347. }
  348. void Shift (int start, int delta)
  349. {
  350. if (delta < 0)
  351. start -= delta;
  352. if (start < _size)
  353. Array.Copy (_items, start, _items, start + delta, _size - start);
  354. _size += delta;
  355. if (delta < 0)
  356. Array.Clear (_items, _size, -delta);
  357. }
  358. void CheckIndex (int index)
  359. {
  360. if (index < 0 || (uint) index > (uint) _size)
  361. throw new ArgumentOutOfRangeException ("index");
  362. }
  363. public void Insert (int index, T item)
  364. {
  365. CheckIndex (index);
  366. if (_size == _items.Length)
  367. GrowIfNeeded (1);
  368. Shift (index, 1);
  369. _items[index] = item;
  370. _version++;
  371. }
  372. public void InsertRange (int index, IEnumerable <T> collection)
  373. {
  374. if (collection == null)
  375. throw new ArgumentNullException ("collection");
  376. CheckIndex (index);
  377. if (collection == this) {
  378. T[] buffer = new T[_size];
  379. CopyTo (buffer, 0);
  380. GrowIfNeeded (_size);
  381. Shift (index, buffer.Length);
  382. Array.Copy (buffer, 0, _items, index, buffer.Length);
  383. } else {
  384. ICollection <T> c = collection as ICollection <T>;
  385. if (c != null)
  386. InsertCollection (index, c);
  387. else
  388. InsertEnumeration (index, collection);
  389. }
  390. _version++;
  391. }
  392. void InsertCollection (int index, ICollection <T> collection)
  393. {
  394. int collectionCount = collection.Count;
  395. GrowIfNeeded (collectionCount);
  396. Shift (index, collectionCount);
  397. collection.CopyTo (_items, index);
  398. }
  399. void InsertEnumeration (int index, IEnumerable <T> enumerable)
  400. {
  401. foreach (T t in enumerable)
  402. Insert (index++, t);
  403. }
  404. public int LastIndexOf (T item)
  405. {
  406. if (_size == 0)
  407. return -1;
  408. return Array.LastIndexOf<T> (_items, item, _size - 1, _size);
  409. }
  410. public int LastIndexOf (T item, int index)
  411. {
  412. CheckIndex (index);
  413. return Array.LastIndexOf<T> (_items, item, index, index + 1);
  414. }
  415. public int LastIndexOf (T item, int index, int count)
  416. {
  417. if (index < 0)
  418. throw new ArgumentOutOfRangeException ("index", index, "index is negative");
  419. if (count < 0)
  420. throw new ArgumentOutOfRangeException ("count", count, "count is negative");
  421. if (index - count + 1 < 0)
  422. throw new ArgumentOutOfRangeException ("cound", count, "count is too large");
  423. return Array.LastIndexOf<T> (_items, item, index, count);
  424. }
  425. public bool Remove (T item)
  426. {
  427. int loc = IndexOf (item);
  428. if (loc != -1)
  429. RemoveAt (loc);
  430. return loc != -1;
  431. }
  432. public int RemoveAll (Predicate <T> match)
  433. {
  434. CheckMatch(match);
  435. int i = 0;
  436. int j = 0;
  437. // Find the first item to remove
  438. for (i = 0; i < _size; i++)
  439. if (match(_items[i]))
  440. break;
  441. if (i == _size)
  442. return 0;
  443. _version++;
  444. // Remove any additional items
  445. for (j = i + 1; j < _size; j++)
  446. {
  447. if (!match(_items[j]))
  448. _items[i++] = _items[j];
  449. }
  450. if (j - i > 0)
  451. Array.Clear (_items, i, j - i);
  452. _size = i;
  453. return (j - i);
  454. }
  455. public void RemoveAt (int index)
  456. {
  457. if (index < 0 || (uint)index >= (uint)_size)
  458. throw new ArgumentOutOfRangeException("index");
  459. Shift (index, -1);
  460. Array.Clear (_items, _size, 1);
  461. _version++;
  462. }
  463. public void RemoveRange (int index, int count)
  464. {
  465. CheckRange (index, count);
  466. if (count > 0) {
  467. Shift (index, -count);
  468. Array.Clear (_items, _size, count);
  469. _version++;
  470. }
  471. }
  472. public void Reverse ()
  473. {
  474. Array.Reverse (_items, 0, _size);
  475. _version++;
  476. }
  477. public void Reverse (int index, int count)
  478. {
  479. CheckRange (index, count);
  480. Array.Reverse (_items, index, count);
  481. _version++;
  482. }
  483. public void Sort ()
  484. {
  485. Array.Sort<T> (_items, 0, _size);
  486. _version++;
  487. }
  488. public void Sort (IComparer <T> comparer)
  489. {
  490. Array.Sort<T> (_items, 0, _size, comparer);
  491. _version++;
  492. }
  493. public void Sort (Comparison <T> comparison)
  494. {
  495. if (comparison == null)
  496. throw new ArgumentNullException ("comparison");
  497. Array.SortImpl<T> (_items, _size, comparison);
  498. _version++;
  499. }
  500. public void Sort (int index, int count, IComparer <T> comparer)
  501. {
  502. CheckRange (index, count);
  503. Array.Sort<T> (_items, index, count, comparer);
  504. _version++;
  505. }
  506. public T [] ToArray ()
  507. {
  508. T [] t = new T [_size];
  509. Array.Copy (_items, t, _size);
  510. return t;
  511. }
  512. public void TrimExcess ()
  513. {
  514. Capacity = _size;
  515. }
  516. public bool TrueForAll (Predicate <T> match)
  517. {
  518. CheckMatch (match);
  519. for (int i = 0; i < _size; i++)
  520. if (!match(_items[i]))
  521. return false;
  522. return true;
  523. }
  524. public int Capacity {
  525. get {
  526. return _items.Length;
  527. }
  528. set {
  529. if ((uint) value < (uint) _size)
  530. throw new ArgumentOutOfRangeException ();
  531. Array.Resize (ref _items, value);
  532. }
  533. }
  534. public int Count {
  535. get { return _size; }
  536. }
  537. public T this [int index] {
  538. [MethodImpl ((MethodImplOptions)256)]
  539. get {
  540. if ((uint) index >= (uint) _size)
  541. throw new ArgumentOutOfRangeException ("index");
  542. return Array.UnsafeLoad (_items, index);
  543. }
  544. [MethodImpl ((MethodImplOptions)256)]
  545. set {
  546. if ((uint) index >= (uint) _size)
  547. throw new ArgumentOutOfRangeException ("index");
  548. _items [index] = value;
  549. _version++;
  550. }
  551. }
  552. #region Interface implementations.
  553. IEnumerator <T> IEnumerable <T>.GetEnumerator ()
  554. {
  555. return GetEnumerator ();
  556. }
  557. void ICollection.CopyTo (Array array, int arrayIndex)
  558. {
  559. if (array == null)
  560. throw new ArgumentNullException ("array");
  561. if (array.Rank > 1 || array.GetLowerBound (0) != 0)
  562. throw new ArgumentException ("Array must be zero based and single dimentional", "array");
  563. Array.Copy (_items, 0, array, arrayIndex, _size);
  564. }
  565. IEnumerator IEnumerable.GetEnumerator ()
  566. {
  567. return GetEnumerator ();
  568. }
  569. int IList.Add (object item)
  570. {
  571. try {
  572. Add ((T) item);
  573. return _size - 1;
  574. } catch (NullReferenceException) {
  575. } catch (InvalidCastException) {
  576. }
  577. throw new ArgumentException ("item");
  578. }
  579. bool IList.Contains (object item)
  580. {
  581. try {
  582. return Contains ((T) item);
  583. } catch (NullReferenceException) {
  584. } catch (InvalidCastException) {
  585. }
  586. return false;
  587. }
  588. int IList.IndexOf (object item)
  589. {
  590. try {
  591. return IndexOf ((T) item);
  592. } catch (NullReferenceException) {
  593. } catch (InvalidCastException) {
  594. }
  595. return -1;
  596. }
  597. void IList.Insert (int index, object item)
  598. {
  599. // We need to check this first because, even if the
  600. // item is null or not the correct type, we need to
  601. // return an ArgumentOutOfRange exception if the
  602. // index is out of range
  603. CheckIndex (index);
  604. try {
  605. Insert (index, (T) item);
  606. return;
  607. } catch (NullReferenceException) {
  608. } catch (InvalidCastException) {
  609. }
  610. throw new ArgumentException ("item");
  611. }
  612. void IList.Remove (object item)
  613. {
  614. try {
  615. Remove ((T) item);
  616. return;
  617. } catch (NullReferenceException) {
  618. } catch (InvalidCastException) {
  619. }
  620. // Swallow the exception--if we can't cast to the
  621. // correct type then we've already "succeeded" in
  622. // removing the item from the List.
  623. }
  624. bool ICollection <T>.IsReadOnly {
  625. get { return false; }
  626. }
  627. bool ICollection.IsSynchronized {
  628. get { return false; }
  629. }
  630. object ICollection.SyncRoot {
  631. get { return this; }
  632. }
  633. bool IList.IsFixedSize {
  634. get { return false; }
  635. }
  636. bool IList.IsReadOnly {
  637. get { return false; }
  638. }
  639. object IList.this [int index] {
  640. get { return this [index]; }
  641. set {
  642. try {
  643. this [index] = (T) value;
  644. return;
  645. } catch (NullReferenceException) {
  646. // can happen when 'value' is null and T is a valuetype
  647. } catch (InvalidCastException) {
  648. }
  649. throw new ArgumentException ("value");
  650. }
  651. }
  652. #endregion
  653. [Serializable]
  654. public struct Enumerator : IEnumerator <T>, IDisposable {
  655. readonly List<T> l;
  656. int next;
  657. readonly int ver;
  658. T current;
  659. internal Enumerator (List <T> l)
  660. : this ()
  661. {
  662. this.l = l;
  663. ver = l._version;
  664. }
  665. public void Dispose ()
  666. {
  667. }
  668. public bool MoveNext ()
  669. {
  670. var list = l;
  671. if ((uint)next < (uint)list._size && ver == list._version) {
  672. current = list._items [next++];
  673. return true;
  674. }
  675. if (ver != l._version)
  676. throw new InvalidOperationException ("Collection was modified; enumeration operation may not execute.");
  677. next = -1;
  678. return false;
  679. }
  680. public T Current {
  681. get { return current; }
  682. }
  683. void IEnumerator.Reset ()
  684. {
  685. if (ver != l._version)
  686. throw new InvalidOperationException ("Collection was modified; enumeration operation may not execute.");
  687. next = 0;
  688. }
  689. object IEnumerator.Current {
  690. get {
  691. if (ver != l._version)
  692. throw new InvalidOperationException ("Collection was modified; enumeration operation may not execute.");
  693. if (next <= 0)
  694. throw new InvalidOperationException ();
  695. return current;
  696. }
  697. }
  698. }
  699. }
  700. }