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

/mcs/class/Mono.C5/C5/arrays/HashedArrayList.cs

https://bitbucket.org/danipen/mono
C# | 2638 lines | 1580 code | 240 blank | 818 comment | 284 complexity | 9c412385ced9bea89375a999fd029b23 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

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
  3. Permission is hereby granted, free of charge, to any person obtaining a copy
  4. of this software and associated documentation files (the "Software"), to deal
  5. in the Software without restriction, including without limitation the rights
  6. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. copies of the Software, and to permit persons to whom the Software is
  8. furnished to do so, subject to the following conditions:
  9. The above copyright notice and this permission notice shall be included in
  10. all copies or substantial portions of the Software.
  11. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  12. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  13. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  14. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  15. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  16. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  17. SOFTWARE.
  18. */
  19. #define HASHINDEX
  20. using System;
  21. using System.Diagnostics;
  22. using SCG = System.Collections.Generic;
  23. namespace C5
  24. {
  25. /// <summary>
  26. /// A list collection based on a plain dynamic array data structure.
  27. /// Expansion of the internal array is performed by doubling on demand.
  28. /// The internal array is only shrinked by the Clear method.
  29. ///
  30. /// <i>When the FIFO property is set to false this class works fine as a stack of T.
  31. /// When the FIFO property is set to true the class will function as a (FIFO) queue
  32. /// but very inefficiently, use a LinkedList (<see cref="T:C5.LinkedList`1"/>) instead.</i>
  33. /// </summary>
  34. [Serializable]
  35. public class HashedArrayList<T> : ArrayBase<T>, IList<T>, SCG.IList<T>
  36. #if HASHINDEX
  37. #else
  38. , IStack<T>, IQueue<T>
  39. #endif
  40. {
  41. #region Fields
  42. /// <summary>
  43. /// Has this list or view not been invalidated by some operation (by someone calling Dispose())
  44. /// </summary>
  45. bool isValid = true;
  46. //TODO: wonder if we should save some memory on none-view situations by
  47. // putting these three fields into a single ref field?
  48. /// <summary>
  49. /// The underlying list if we are a view, null else.
  50. /// </summary>
  51. HashedArrayList<T> underlying;
  52. WeakViewList<HashedArrayList<T>> views;
  53. WeakViewList<HashedArrayList<T>>.Node myWeakReference;
  54. /// <summary>
  55. /// The size of the underlying list.
  56. /// </summary>
  57. int underlyingsize { get { return (underlying ?? this).size; } }
  58. /// <summary>
  59. /// The underlying field of the FIFO property
  60. /// </summary>
  61. bool fIFO = false;
  62. #if HASHINDEX
  63. HashSet<KeyValuePair<T, int>> itemIndex;
  64. #endif
  65. #endregion
  66. #region Events
  67. /// <summary>
  68. ///
  69. /// </summary>
  70. /// <value></value>
  71. public override EventTypeEnum ListenableEvents { get { return underlying == null ? EventTypeEnum.All : EventTypeEnum.None; } }
  72. /*
  73. /// <summary>
  74. ///
  75. /// </summary>
  76. /// <value></value>
  77. public override event CollectionChangedHandler<T> CollectionChanged
  78. {
  79. add
  80. {
  81. if (underlying == null)
  82. base.CollectionChanged += value;
  83. else
  84. throw new UnlistenableEventException("Can't listen to a view");
  85. }
  86. remove
  87. {
  88. if (underlying == null)
  89. base.CollectionChanged -= value;
  90. else
  91. throw new UnlistenableEventException("Can't listen to a view");
  92. }
  93. }
  94. /// <summary>
  95. ///
  96. /// </summary>
  97. /// <value></value>
  98. public override event CollectionClearedHandler<T> CollectionCleared
  99. {
  100. add
  101. {
  102. if (underlying == null)
  103. base.CollectionCleared += value;
  104. else
  105. throw new UnlistenableEventException("Can't listen to a view");
  106. }
  107. remove
  108. {
  109. if (underlying == null)
  110. base.CollectionCleared -= value;
  111. else
  112. throw new UnlistenableEventException("Can't listen to a view");
  113. }
  114. }
  115. /// <summary>
  116. ///
  117. /// </summary>
  118. /// <value></value>
  119. public override event ItemsAddedHandler<T> ItemsAdded
  120. {
  121. add
  122. {
  123. if (underlying == null)
  124. base.ItemsAdded += value;
  125. else
  126. throw new UnlistenableEventException("Can't listen to a view");
  127. }
  128. remove
  129. {
  130. if (underlying == null)
  131. base.ItemsAdded -= value;
  132. else
  133. throw new UnlistenableEventException("Can't listen to a view");
  134. }
  135. }
  136. /// <summary>
  137. ///
  138. /// </summary>
  139. /// <value></value>
  140. public override event ItemInsertedHandler<T> ItemInserted
  141. {
  142. add
  143. {
  144. if (underlying == null)
  145. base.ItemInserted += value;
  146. else
  147. throw new UnlistenableEventException("Can't listen to a view");
  148. }
  149. remove
  150. {
  151. if (underlying == null)
  152. base.ItemInserted -= value;
  153. else
  154. throw new UnlistenableEventException("Can't listen to a view");
  155. }
  156. }
  157. /// <summary>
  158. ///
  159. /// </summary>
  160. /// <value></value>
  161. public override event ItemsRemovedHandler<T> ItemsRemoved
  162. {
  163. add
  164. {
  165. if (underlying == null)
  166. base.ItemsRemoved += value;
  167. else
  168. throw new UnlistenableEventException("Can't listen to a view");
  169. }
  170. remove
  171. {
  172. if (underlying == null)
  173. base.ItemsRemoved -= value;
  174. else
  175. throw new UnlistenableEventException("Can't listen to a view");
  176. }
  177. }
  178. /// <summary>
  179. ///
  180. /// </summary>
  181. /// <value></value>
  182. public override event ItemRemovedAtHandler<T> ItemRemovedAt
  183. {
  184. add
  185. {
  186. if (underlying == null)
  187. base.ItemRemovedAt += value;
  188. else
  189. throw new UnlistenableEventException("Can't listen to a view");
  190. }
  191. remove
  192. {
  193. if (underlying == null)
  194. base.ItemRemovedAt -= value;
  195. else
  196. throw new UnlistenableEventException("Can't listen to a view");
  197. }
  198. }
  199. */
  200. #endregion
  201. #region Util
  202. bool equals(T i1, T i2) { return itemequalityComparer.Equals(i1, i2); }
  203. /// <summary>
  204. /// Increment or decrement the private size fields
  205. /// </summary>
  206. /// <param name="delta">Increment (with sign)</param>
  207. void addtosize(int delta)
  208. {
  209. size += delta;
  210. if (underlying != null)
  211. underlying.size += delta;
  212. }
  213. #region Array handling
  214. /// <summary>
  215. /// Double the size of the internal array.
  216. /// </summary>
  217. protected override void expand()
  218. { expand(2 * array.Length, underlyingsize); }
  219. /// <summary>
  220. /// Expand the internal array, resetting the index of the first unused element.
  221. /// </summary>
  222. /// <param name="newcapacity">The new capacity (will be rouded upwards to a power of 2).</param>
  223. /// <param name="newsize">The new count of </param>
  224. protected override void expand(int newcapacity, int newsize)
  225. {
  226. if (underlying != null)
  227. underlying.expand(newcapacity, newsize);
  228. else
  229. {
  230. base.expand(newcapacity, newsize);
  231. if (views != null)
  232. foreach (HashedArrayList<T> v in views)
  233. v.array = array;
  234. }
  235. }
  236. #endregion
  237. #region Checks
  238. /// <summary>
  239. /// Check if it is valid to perform updates and increment stamp if so.
  240. /// </summary>
  241. /// <exception cref="ViewDisposedException"> If check fails by this list being a disposed view.</exception>
  242. /// <exception cref="ReadOnlyCollectionException"> If check fails by this being a read only list.</exception>
  243. protected override void updatecheck()
  244. {
  245. validitycheck();
  246. base.updatecheck();
  247. if (underlying != null)
  248. underlying.stamp++;
  249. }
  250. /// <summary>
  251. /// Check if we are a view that the underlying list has only been updated through us.
  252. /// <para>This method should be called from enumerators etc to guard against
  253. /// modification of the base collection.</para>
  254. /// </summary>
  255. /// <exception cref="ViewDisposedException"> if check fails.</exception>
  256. void validitycheck()
  257. {
  258. if (!isValid)
  259. throw new ViewDisposedException();
  260. }
  261. /// <summary>
  262. /// Check that the list has not been updated since a particular time.
  263. /// <para>To be used by enumerators and range </para>
  264. /// </summary>
  265. /// <exception cref="ViewDisposedException"> If check fails by this list being a disposed view.</exception>
  266. /// <exception cref="CollectionModifiedException">If the list *has* beeen updated since that time..</exception>
  267. /// <param name="stamp">The stamp indicating the time.</param>
  268. protected override void modifycheck(int stamp)
  269. {
  270. validitycheck();
  271. if (this.stamp != stamp)
  272. throw new CollectionModifiedException();
  273. }
  274. #endregion
  275. #region Searching
  276. /// <summary>
  277. /// Internal version of IndexOf without modification checks.
  278. /// </summary>
  279. /// <param name="item">Item to look for</param>
  280. /// <returns>The index of first occurrence</returns>
  281. int indexOf(T item)
  282. {
  283. #if HASHINDEX
  284. KeyValuePair<T, int> p = new KeyValuePair<T, int>(item);
  285. if (itemIndex.Find(ref p) && p.Value >= offset && p.Value < offset + size)
  286. return p.Value - offset;
  287. #else
  288. for (int i = 0; i < size; i++)
  289. if (equals(item, array[offset + i]))
  290. return i;
  291. #endif
  292. return ~size;
  293. }
  294. /// <summary>
  295. /// Internal version of LastIndexOf without modification checks.
  296. /// </summary>
  297. /// <param name="item">Item to look for</param>
  298. /// <returns>The index of last occurrence</returns>
  299. int lastIndexOf(T item)
  300. {
  301. #if HASHINDEX
  302. return indexOf(item);
  303. #else
  304. for (int i = size - 1; i >= 0; i--)
  305. if (equals(item, array[offset + i]))
  306. return i;
  307. return ~size;
  308. #endif
  309. }
  310. #endregion
  311. #region Inserting
  312. #if HASHINDEX
  313. /// <summary>
  314. /// Internal version of Insert with no modification checks.
  315. /// </summary>
  316. /// <exception cref="DuplicateNotAllowedException"> if item already in list.</exception>
  317. /// <param name="i">Index to insert at</param>
  318. /// <param name="item">Item to insert</param>
  319. #else
  320. /// <summary>
  321. /// Internal version of Insert with no modification checks.
  322. /// </summary>
  323. /// <param name="i">Index to insert at</param>
  324. /// <param name="item">Item to insert</param>
  325. #endif
  326. protected override void insert(int i, T item)
  327. {
  328. #if HASHINDEX
  329. KeyValuePair<T, int> p = new KeyValuePair<T, int>(item, offset + i);
  330. if (itemIndex.FindOrAdd(ref p))
  331. throw new DuplicateNotAllowedException("Item already in indexed list: " + item);
  332. #endif
  333. baseinsert(i, item);
  334. #if HASHINDEX
  335. reindex(i + offset + 1);
  336. #endif
  337. }
  338. private void baseinsert(int i, T item)
  339. {
  340. if (underlyingsize == array.Length)
  341. expand();
  342. i += offset;
  343. if (i < underlyingsize)
  344. Array.Copy(array, i, array, i + 1, underlyingsize - i);
  345. array[i] = item;
  346. addtosize(1);
  347. fixViewsAfterInsert(1, i);
  348. }
  349. #endregion
  350. #region Removing
  351. /// <summary>
  352. /// Internal version of RemoveAt with no modification checks.
  353. /// </summary>
  354. /// <param name="i">Index to remove at</param>
  355. /// <returns>The removed item</returns>
  356. T removeAt(int i)
  357. {
  358. i += offset;
  359. fixViewsBeforeSingleRemove(i);
  360. T retval = array[i];
  361. addtosize(-1);
  362. if (underlyingsize > i)
  363. Array.Copy(array, i + 1, array, i, underlyingsize - i);
  364. array[underlyingsize] = default(T);
  365. #if HASHINDEX
  366. itemIndex.Remove(new KeyValuePair<T, int>(retval));
  367. reindex(i);
  368. #endif
  369. return retval;
  370. }
  371. #endregion
  372. #region Indexing
  373. #if HASHINDEX
  374. private void reindex(int start) { reindex(start, underlyingsize); }
  375. private void reindex(int start, int end)
  376. {
  377. for (int j = start; j < end; j++)
  378. itemIndex.UpdateOrAdd(new KeyValuePair<T, int>(array[j], j));
  379. }
  380. #endif
  381. #endregion
  382. #region fixView utilities
  383. /// <summary>
  384. ///
  385. /// </summary>
  386. /// <param name="added">The actual number of inserted nodes</param>
  387. /// <param name="realInsertionIndex"></param>
  388. void fixViewsAfterInsert(int added, int realInsertionIndex)
  389. {
  390. if (views != null)
  391. foreach (HashedArrayList<T> view in views)
  392. {
  393. if (view != this)
  394. {
  395. if (view.offset < realInsertionIndex && view.offset + view.size > realInsertionIndex)
  396. view.size += added;
  397. if (view.offset > realInsertionIndex || (view.offset == realInsertionIndex && view.size > 0))
  398. view.offset += added;
  399. }
  400. }
  401. }
  402. void fixViewsBeforeSingleRemove(int realRemovalIndex)
  403. {
  404. if (views != null)
  405. foreach (HashedArrayList<T> view in views)
  406. {
  407. if (view != this)
  408. {
  409. if (view.offset <= realRemovalIndex && view.offset + view.size > realRemovalIndex)
  410. view.size--;
  411. if (view.offset > realRemovalIndex)
  412. view.offset--;
  413. }
  414. }
  415. }
  416. /// <summary>
  417. /// Fix offsets and sizes of other views before removing an interval from this
  418. /// </summary>
  419. /// <param name="start">the start of the interval relative to the array/underlying</param>
  420. /// <param name="count"></param>
  421. void fixViewsBeforeRemove(int start, int count)
  422. {
  423. int clearend = start + count - 1;
  424. if (views != null)
  425. foreach (HashedArrayList<T> view in views)
  426. {
  427. if (view == this)
  428. continue;
  429. int viewoffset = view.offset, viewend = viewoffset + view.size - 1;
  430. if (start < viewoffset)
  431. {
  432. if (clearend < viewoffset)
  433. view.offset = viewoffset - count;
  434. else
  435. {
  436. view.offset = start;
  437. view.size = clearend < viewend ? viewend - clearend : 0;
  438. }
  439. }
  440. else if (start <= viewend)
  441. view.size = clearend <= viewend ? view.size - count : start - viewoffset;
  442. }
  443. }
  444. /// <summary>
  445. ///
  446. /// </summary>
  447. /// <param name="otherOffset"></param>
  448. /// <param name="otherSize"></param>
  449. /// <returns>The position of View(otherOffset, otherSize) wrt. this view</returns>
  450. MutualViewPosition viewPosition(int otherOffset, int otherSize)
  451. {
  452. int end = offset + size, otherEnd = otherOffset + otherSize;
  453. if (otherOffset >= end || otherEnd <= offset)
  454. return MutualViewPosition.NonOverlapping;
  455. if (size == 0 || (otherOffset <= offset && end <= otherEnd))
  456. return MutualViewPosition.Contains;
  457. if (otherSize == 0 || (offset <= otherOffset && otherEnd <= end))
  458. return MutualViewPosition.ContainedIn;
  459. return MutualViewPosition.Overlapping;
  460. }
  461. //TODO: make version that fits the new, more forgiving rules for disposing
  462. void disposeOverlappingViews(bool reverse)
  463. {
  464. if (views != null)
  465. foreach (HashedArrayList<T> view in views)
  466. {
  467. if (view != this)
  468. {
  469. switch (viewPosition(view.offset, view.size))
  470. {
  471. case MutualViewPosition.ContainedIn:
  472. if (reverse)
  473. view.offset = 2 * offset + size - view.size - view.offset;
  474. else
  475. view.Dispose();
  476. break;
  477. case MutualViewPosition.Overlapping:
  478. view.Dispose();
  479. break;
  480. case MutualViewPosition.Contains:
  481. case MutualViewPosition.NonOverlapping:
  482. break;
  483. }
  484. }
  485. }
  486. }
  487. #endregion
  488. #endregion
  489. #region Position, PositionComparer and ViewHandler nested types
  490. class PositionComparer : SCG.IComparer<Position>
  491. {
  492. public int Compare(Position a, Position b)
  493. {
  494. return a.index.CompareTo(b.index);
  495. }
  496. }
  497. /// <summary>
  498. /// During RemoveAll, we need to cache the original endpoint indices of views (??? also for HashedArrayList?)
  499. /// </summary>
  500. struct Position
  501. {
  502. public readonly HashedArrayList<T> view;
  503. public readonly int index;
  504. public Position(HashedArrayList<T> view, bool left)
  505. {
  506. this.view = view;
  507. index = left ? view.offset : view.offset + view.size - 1;
  508. }
  509. public Position(int index) { this.index = index; view = null; }
  510. }
  511. /// <summary>
  512. /// Handle the update of (other) views during a multi-remove operation.
  513. /// </summary>
  514. struct ViewHandler
  515. {
  516. HashedArrayList<Position> leftEnds;
  517. HashedArrayList<Position> rightEnds;
  518. int leftEndIndex, rightEndIndex;
  519. internal readonly int viewCount;
  520. internal ViewHandler(HashedArrayList<T> list)
  521. {
  522. leftEndIndex = rightEndIndex = viewCount = 0;
  523. leftEnds = rightEnds = null;
  524. if (list.views != null)
  525. foreach (HashedArrayList<T> v in list.views)
  526. if (v != list)
  527. {
  528. if (leftEnds == null)
  529. {
  530. leftEnds = new HashedArrayList<Position>();
  531. rightEnds = new HashedArrayList<Position>();
  532. }
  533. leftEnds.Add(new Position(v, true));
  534. rightEnds.Add(new Position(v, false));
  535. }
  536. if (leftEnds == null)
  537. return;
  538. viewCount = leftEnds.Count;
  539. leftEnds.Sort(new PositionComparer());
  540. rightEnds.Sort(new PositionComparer());
  541. }
  542. /// <summary>
  543. /// This is to be called with realindex pointing to the first node to be removed after a (stretch of) node that was not removed
  544. /// </summary>
  545. /// <param name="removed"></param>
  546. /// <param name="realindex"></param>
  547. internal void skipEndpoints(int removed, int realindex)
  548. {
  549. if (viewCount > 0)
  550. {
  551. Position endpoint;
  552. while (leftEndIndex < viewCount && (endpoint = leftEnds[leftEndIndex]).index <= realindex)
  553. {
  554. HashedArrayList<T> view = endpoint.view;
  555. view.offset = view.offset - removed;
  556. view.size += removed;
  557. leftEndIndex++;
  558. }
  559. while (rightEndIndex < viewCount && (endpoint = rightEnds[rightEndIndex]).index < realindex)
  560. {
  561. endpoint.view.size -= removed;
  562. rightEndIndex++;
  563. }
  564. }
  565. }
  566. internal void updateViewSizesAndCounts(int removed, int realindex)
  567. {
  568. if (viewCount > 0)
  569. {
  570. Position endpoint;
  571. while (leftEndIndex < viewCount && (endpoint = leftEnds[leftEndIndex]).index <= realindex)
  572. {
  573. HashedArrayList<T> view = endpoint.view;
  574. view.offset = view.Offset - removed;
  575. view.size += removed;
  576. leftEndIndex++;
  577. }
  578. while (rightEndIndex < viewCount && (endpoint = rightEnds[rightEndIndex]).index < realindex)
  579. {
  580. endpoint.view.size -= removed;
  581. rightEndIndex++;
  582. }
  583. }
  584. }
  585. }
  586. #endregion
  587. #region Constructors
  588. /// <summary>
  589. /// Create an array list with default item equalityComparer and initial capacity 8 items.
  590. /// </summary>
  591. public HashedArrayList() : this(8) { }
  592. /// <summary>
  593. /// Create an array list with external item equalityComparer and initial capacity 8 items.
  594. /// </summary>
  595. /// <param name="itemequalityComparer">The external item equalityComparer</param>
  596. public HashedArrayList(SCG.IEqualityComparer<T> itemequalityComparer) : this(8, itemequalityComparer) { }
  597. /// <summary>
  598. /// Create an array list with default item equalityComparer and prescribed initial capacity.
  599. /// </summary>
  600. /// <param name="capacity">The prescribed capacity</param>
  601. public HashedArrayList(int capacity) : this(capacity, EqualityComparer<T>.Default) { }
  602. /// <summary>
  603. /// Create an array list with external item equalityComparer and prescribed initial capacity.
  604. /// </summary>
  605. /// <param name="capacity">The prescribed capacity</param>
  606. /// <param name="itemequalityComparer">The external item equalityComparer</param>
  607. public HashedArrayList(int capacity, SCG.IEqualityComparer<T> itemequalityComparer)
  608. : base(capacity, itemequalityComparer)
  609. {
  610. #if HASHINDEX
  611. itemIndex = new HashSet<KeyValuePair<T, int>>(new KeyValuePairEqualityComparer<T, int>(itemequalityComparer));
  612. #endif
  613. }
  614. #endregion
  615. #region IList<T> Members
  616. /// <summary>
  617. /// </summary>
  618. /// <exception cref="NoSuchItemException"> if this list is empty.</exception>
  619. /// <value>The first item in this list.</value>
  620. [Tested]
  621. public virtual T First
  622. {
  623. [Tested]
  624. get
  625. {
  626. validitycheck();
  627. if (size == 0)
  628. throw new NoSuchItemException();
  629. return array[offset];
  630. }
  631. }
  632. /// <summary>
  633. /// </summary>
  634. /// <exception cref="NoSuchItemException"> if this list is empty.</exception>
  635. /// <value>The last item in this list.</value>
  636. [Tested]
  637. public virtual T Last
  638. {
  639. [Tested]
  640. get
  641. {
  642. validitycheck();
  643. if (size == 0)
  644. throw new NoSuchItemException();
  645. return array[offset + size - 1];
  646. }
  647. }
  648. /// <summary>
  649. /// Since <code>Add(T item)</code> always add at the end of the list,
  650. /// this describes if list has FIFO or LIFO semantics.
  651. /// </summary>
  652. /// <value>True if the <code>Remove()</code> operation removes from the
  653. /// start of the list, false if it removes from the end. The default for a new array list is false.</value>
  654. [Tested]
  655. public virtual bool FIFO
  656. {
  657. [Tested]
  658. get { validitycheck(); return fIFO; }
  659. [Tested]
  660. set { updatecheck(); fIFO = value; }
  661. }
  662. /// <summary>
  663. ///
  664. /// </summary>
  665. public virtual bool IsFixedSize
  666. {
  667. get { validitycheck(); return false; }
  668. }
  669. #if HASHINDEX
  670. /// <summary>
  671. /// On this list, this indexer is read/write.
  672. /// </summary>
  673. /// <exception cref="IndexOutOfRangeException"> if index is negative or
  674. /// &gt;= the size of the collection.</exception>
  675. /// <exception cref="DuplicateNotAllowedException"> By the get operation
  676. /// if the item already is present somewhere else in the list.</exception>
  677. /// <value>The index'th item of this list.</value>
  678. /// <param name="index">The index of the item to fetch or store.</param>
  679. #else
  680. /// <summary>
  681. /// On this list, this indexer is read/write.
  682. /// </summary>
  683. /// <exception cref="IndexOutOfRangeException"> if index is negative or
  684. /// &gt;= the size of the collection.</exception>
  685. /// <value>The index'th item of this list.</value>
  686. /// <param name="index">The index of the item to fetch or store.</param>
  687. #endif
  688. [Tested]
  689. public virtual T this[int index]
  690. {
  691. [Tested]
  692. get
  693. {
  694. validitycheck();
  695. if (index < 0 || index >= size)
  696. throw new IndexOutOfRangeException();
  697. return array[offset + index];
  698. }
  699. [Tested]
  700. set
  701. {
  702. updatecheck();
  703. if (index < 0 || index >= size)
  704. throw new IndexOutOfRangeException();
  705. index += offset;
  706. T item = array[index];
  707. #if HASHINDEX
  708. KeyValuePair<T, int> p = new KeyValuePair<T, int>(value, index);
  709. if (itemequalityComparer.Equals(value, item))
  710. {
  711. array[index] = value;
  712. itemIndex.Update(p);
  713. }
  714. else if (!itemIndex.FindOrAdd(ref p))
  715. {
  716. itemIndex.Remove(new KeyValuePair<T, int>(item));
  717. array[index] = value;
  718. }
  719. else
  720. throw new DuplicateNotAllowedException("Item already in indexed list");
  721. #else
  722. array[index] = value;
  723. #endif
  724. (underlying ?? this).raiseForSetThis(index, value, item);
  725. }
  726. }
  727. /// <summary>
  728. ///
  729. /// </summary>
  730. /// <value></value>
  731. public virtual Speed IndexingSpeed { get { return Speed.Constant; } }
  732. #if HASHINDEX
  733. /// <summary>
  734. /// Insert an item at a specific index location in this list.
  735. ///</summary>
  736. /// <exception cref="IndexOutOfRangeException"> if index is negative or
  737. /// &gt; the size of the collection. </exception>
  738. /// <exception cref="DuplicateNotAllowedException">
  739. /// If the item is already present in the list.</exception>
  740. /// <param name="index">The index at which to insert.</param>
  741. /// <param name="item">The item to insert.</param>
  742. #else
  743. /// <summary>
  744. /// Insert an item at a specific index location in this list.
  745. ///</summary>
  746. /// <exception cref="IndexOutOfRangeException"> if i is negative or
  747. /// &gt; the size of the collection. </exception>
  748. /// <param name="index">The index at which to insert.</param>
  749. /// <param name="item">The item to insert.</param>
  750. #endif
  751. [Tested]
  752. public virtual void Insert(int index, T item)
  753. {
  754. updatecheck();
  755. if (index < 0 || index > size)
  756. throw new IndexOutOfRangeException();
  757. insert(index, item);
  758. (underlying ?? this).raiseForInsert(index + offset, item);
  759. }
  760. /// <summary>
  761. /// Insert an item at the end of a compatible view, used as a pointer.
  762. /// <para>The <code>pointer</code> must be a view on the same list as
  763. /// <code>this</code> and the endpoitn of <code>pointer</code> must be
  764. /// a valid insertion point of <code>this</code></para>
  765. /// </summary>
  766. /// <exception cref="IncompatibleViewException">If <code>pointer</code>
  767. /// is not a view on or the same list as <code>this</code></exception>
  768. /// <exception cref="IndexOutOfRangeException"><b>??????</b> if the endpoint of
  769. /// <code>pointer</code> is not inside <code>this</code></exception>
  770. /// <exception cref="DuplicateNotAllowedException"> if the list has
  771. /// <code>AllowsDuplicates==false</code> and the item is
  772. /// already in the list.</exception>
  773. /// <param name="pointer"></param>
  774. /// <param name="item"></param>
  775. public void Insert(IList<T> pointer, T item)
  776. {
  777. if ((pointer == null) || ((pointer.Underlying ?? pointer) != (underlying ?? this)))
  778. throw new IncompatibleViewException();
  779. Insert(pointer.Offset + pointer.Count - Offset, item);
  780. }
  781. #if HASHINDEX
  782. /// <summary>
  783. /// Insert into this list all items from an enumerable collection starting
  784. /// at a particular index.
  785. /// </summary>
  786. /// <exception cref="IndexOutOfRangeException"> if index is negative or
  787. /// &gt; the size of the collection.</exception>
  788. /// <exception cref="DuplicateNotAllowedException"> If <code>items</code>
  789. /// contains duplicates or some item already present in the list.</exception>
  790. /// <param name="index">Index to start inserting at</param>
  791. /// <param name="items">Items to insert</param>
  792. #else
  793. /// <summary>
  794. /// Insert into this list all items from an enumerable collection starting
  795. /// at a particular index.
  796. /// </summary>
  797. /// <exception cref="IndexOutOfRangeException"> if index is negative or
  798. /// &gt; the size of the collection.</exception>
  799. /// <param name="index">Index to start inserting at</param>
  800. /// <param name="items">Items to insert</param>
  801. /// <typeparam name="U"></typeparam>
  802. #endif
  803. [Tested]
  804. public virtual void InsertAll<U>(int index, SCG.IEnumerable<U> items) where U : T
  805. {
  806. updatecheck();
  807. if (index < 0 || index > size)
  808. throw new IndexOutOfRangeException();
  809. index += offset;
  810. int toadd = EnumerableBase<U>.countItems(items);
  811. if (toadd == 0)
  812. return;
  813. if (toadd + underlyingsize > array.Length)
  814. expand(toadd + underlyingsize, underlyingsize);
  815. if (underlyingsize > index)
  816. Array.Copy(array, index, array, index + toadd, underlyingsize - index);
  817. int i = index;
  818. try
  819. {
  820. foreach (T item in items)
  821. {
  822. #if HASHINDEX
  823. KeyValuePair<T, int> p = new KeyValuePair<T, int>(item, i);
  824. if (itemIndex.FindOrAdd(ref p))
  825. throw new DuplicateNotAllowedException("Item already in indexed list");
  826. #endif
  827. array[i++] = item;
  828. }
  829. }
  830. finally
  831. {
  832. int added = i - index;
  833. if (added < toadd)
  834. {
  835. Array.Copy(array, index + toadd, array, i, underlyingsize - index);
  836. Array.Clear(array, underlyingsize + added, toadd - added);
  837. }
  838. if (added > 0)
  839. {
  840. addtosize(added);
  841. #if HASHINDEX
  842. reindex(i);
  843. #endif
  844. fixViewsAfterInsert(added, index);
  845. (underlying ?? this).raiseForInsertAll(index, added);
  846. }
  847. }
  848. }
  849. private void raiseForInsertAll(int index, int added)
  850. {
  851. if (ActiveEvents != 0)
  852. {
  853. if ((ActiveEvents & (EventTypeEnum.Added | EventTypeEnum.Inserted)) != 0)
  854. for (int j = index; j < index + added; j++)
  855. {
  856. raiseItemInserted(array[j], j);
  857. raiseItemsAdded(array[j], 1);
  858. }
  859. raiseCollectionChanged();
  860. }
  861. }
  862. #if HASHINDEX
  863. /// <summary>
  864. /// Insert an item at the front of this list;
  865. /// </summary>
  866. /// <exception cref="DuplicateNotAllowedException">If the item is already in the list</exception>
  867. /// <param name="item">The item to insert.</param>
  868. #else
  869. /// <summary>
  870. /// Insert an item at the front of this list;
  871. /// </summary>
  872. /// <param name="item">The item to insert.</param>
  873. #endif
  874. [Tested]
  875. public virtual void InsertFirst(T item)
  876. {
  877. updatecheck();
  878. insert(0, item);
  879. (underlying ?? this).raiseForInsert(offset, item);
  880. }
  881. #if HASHINDEX
  882. /// <summary>
  883. /// Insert an item at the back of this list.
  884. /// </summary>
  885. /// <exception cref="DuplicateNotAllowedException">If the item is already in the list</exception>
  886. /// <param name="item">The item to insert.</param>
  887. #else
  888. /// <summary>
  889. /// Insert an item at the back of this list.
  890. /// </summary>
  891. /// <param name="item">The item to insert.</param>
  892. #endif
  893. [Tested]
  894. public virtual void InsertLast(T item)
  895. {
  896. updatecheck();
  897. insert(size, item);
  898. (underlying ?? this).raiseForInsert(size - 1 + offset, item);
  899. }
  900. //NOTE: if the filter throws an exception, no result will be returned.
  901. /// <summary>
  902. /// Create a new list consisting of the items of this list satisfying a
  903. /// certain predicate.
  904. /// <para>The new list will be of type HashedArrayList</para>
  905. /// </summary>
  906. /// <param name="filter">The filter delegate defining the predicate.</param>
  907. /// <returns>The new list.</returns>
  908. [Tested]
  909. public virtual IList<T> FindAll(Fun<T, bool> filter)
  910. {
  911. validitycheck();
  912. int stamp = this.stamp;
  913. HashedArrayList<T> res = new HashedArrayList<T>(itemequalityComparer);
  914. int j = 0, rescap = res.array.Length;
  915. for (int i = 0; i < size; i++)
  916. {
  917. T a = array[offset + i];
  918. bool found = filter(a);
  919. modifycheck(stamp);
  920. if (found)
  921. {
  922. if (j == rescap) res.expand(rescap = 2 * rescap, j);
  923. res.array[j++] = a;
  924. }
  925. }
  926. res.size = j;
  927. #if HASHINDEX
  928. res.reindex(0);
  929. #endif
  930. return res;
  931. }
  932. #if HASHINDEX
  933. /// <summary>
  934. /// Create a new list consisting of the results of mapping all items of this
  935. /// list. The new list will use the default item equalityComparer for the item type V.
  936. /// <para>The new list will be of type HashedArrayList</para>
  937. /// </summary>
  938. /// <exception cref="DuplicateNotAllowedException">If <code>mapper</code>
  939. /// creates duplicates</exception>
  940. /// <typeparam name="V">The type of items of the new list</typeparam>
  941. /// <param name="mapper">The delegate defining the map.</param>
  942. /// <returns>The new list.</returns>
  943. #else
  944. /// <summary>
  945. /// Create a new list consisting of the results of mapping all items of this
  946. /// list. The new list will use the default item equalityComparer for the item type V.
  947. /// <para>The new list will be of type HashedArrayList</para>
  948. /// </summary>
  949. /// <typeparam name="V">The type of items of the new list</typeparam>
  950. /// <param name="mapper">The delegate defining the map.</param>
  951. /// <returns>The new list.</returns>
  952. #endif
  953. [Tested]
  954. public virtual IList<V> Map<V>(Fun<T, V> mapper)
  955. {
  956. validitycheck();
  957. HashedArrayList<V> res = new HashedArrayList<V>(size);
  958. return map<V>(mapper, res);
  959. }
  960. #if HASHINDEX
  961. /// <summary>
  962. /// Create a new list consisting of the results of mapping all items of this
  963. /// list. The new list will use a specified item equalityComparer for the item type.
  964. /// <para>The new list will be of type HashedArrayList</para>
  965. /// </summary>
  966. /// <exception cref="DuplicateNotAllowedException">If <code>mapper</code>
  967. /// creates duplicates</exception>
  968. /// <typeparam name="V">The type of items of the new list</typeparam>
  969. /// <param name="mapper">The delegate defining the map.</param>
  970. /// <param name="itemequalityComparer">The item equalityComparer to use for the new list</param>
  971. /// <returns>The new list.</returns>
  972. #else
  973. /// <summary>
  974. /// Create a new list consisting of the results of mapping all items of this
  975. /// list. The new list will use a specified item equalityComparer for the item type.
  976. /// <para>The new list will be of type HashedArrayList</para>
  977. /// </summary>
  978. /// <typeparam name="V">The type of items of the new list</typeparam>
  979. /// <param name="mapper">The delegate defining the map.</param>
  980. /// <param name="itemequalityComparer">The item equalityComparer to use for the new list</param>
  981. /// <returns>The new list.</returns>
  982. #endif
  983. public virtual IList<V> Map<V>(Fun<T, V> mapper, SCG.IEqualityComparer<V> itemequalityComparer)
  984. {
  985. validitycheck();
  986. HashedArrayList<V> res = new HashedArrayList<V>(size, itemequalityComparer);
  987. return map<V>(mapper, res);
  988. }
  989. private IList<V> map<V>(Fun<T, V> mapper, HashedArrayList<V> res)
  990. {
  991. int stamp = this.stamp;
  992. if (size > 0)
  993. for (int i = 0; i < size; i++)
  994. {
  995. V mappeditem = mapper(array[offset + i]);
  996. modifycheck(stamp);
  997. #if HASHINDEX
  998. KeyValuePair<V, int> p = new KeyValuePair<V, int>(mappeditem, i);
  999. if (res.itemIndex.FindOrAdd(ref p))
  1000. throw new ArgumentException("Mapped item already in indexed list");
  1001. #endif
  1002. res.array[i] = mappeditem;
  1003. }
  1004. res.size = size;
  1005. return res;
  1006. }
  1007. /// <summary>
  1008. /// Remove one item from the list: from the front if <code>FIFO</code>
  1009. /// is true, else from the back.
  1010. /// </summary>
  1011. /// <exception cref="NoSuchItemException"> if this list is empty.</exception>
  1012. /// <returns>The removed item.</returns>
  1013. [Tested]
  1014. public virtual T Remove()
  1015. {
  1016. updatecheck();
  1017. if (size == 0)
  1018. throw new NoSuchItemException("List is empty");
  1019. T item = removeAt(fIFO ? 0 : size - 1);
  1020. (underlying ?? this).raiseForRemove(item);
  1021. return item;
  1022. }
  1023. /// <summary>
  1024. /// Remove one item from the fromnt of the list.
  1025. /// </summary>
  1026. /// <exception cref="NoSuchItemException"> if this list is empty.</exception>
  1027. /// <returns>The removed item.</returns>
  1028. [Tested]
  1029. public virtual T RemoveFirst()
  1030. {
  1031. updatecheck();
  1032. if (size == 0)
  1033. throw new NoSuchItemException("List is empty");
  1034. T item = removeAt(0);
  1035. (underlying ?? this).raiseForRemoveAt(offset, item);
  1036. return item;
  1037. }
  1038. /// <summary>
  1039. /// Remove one item from the back of the list.
  1040. /// </summary>
  1041. /// <exception cref="NoSuchItemException"> if this list is empty.</exception>
  1042. /// <returns>The removed item.</returns>
  1043. [Tested]
  1044. public virtual T RemoveLast()
  1045. {
  1046. updatecheck();
  1047. if (size == 0)
  1048. throw new NoSuchItemException("List is empty");
  1049. T item = removeAt(size - 1);
  1050. (underlying ?? this).raiseForRemoveAt(size + offset, item);
  1051. return item;
  1052. }
  1053. /// <summary>
  1054. /// Create a list view on this list.
  1055. /// </summary>
  1056. /// <exception cref="ArgumentOutOfRangeException"> if the start or count is negative
  1057. /// or the range does not fit within list.</exception>
  1058. /// <param name="start">The index in this list of the start of the view.</param>
  1059. /// <param name="count">The size of the view.</param>
  1060. /// <returns>The new list view.</returns>
  1061. [Tested]
  1062. public virtual IList<T> View(int start, int count)
  1063. {
  1064. validitycheck();
  1065. checkRange(start, count);
  1066. if (views == null)
  1067. views = new WeakViewList<HashedArrayList<T>>();
  1068. HashedArrayList<T> retval = (HashedArrayList<T>)MemberwiseClone();
  1069. retval.underlying = underlying != null ? underlying : this;
  1070. retval.offset = start + offset;
  1071. retval.size = count;
  1072. retval.myWeakReference = views.Add(retval);
  1073. return retval;
  1074. }
  1075. /// <summary>
  1076. /// Create a list view on this list containing the (first) occurrence of a particular item.
  1077. /// <para>Returns <code>null</code> if the item is not in this list.</para>
  1078. /// </summary>
  1079. /// <param name="item">The item to find.</param>
  1080. /// <returns>The new list view.</returns>
  1081. [Tested]
  1082. public virtual IList<T> ViewOf(T item)
  1083. {
  1084. int index = indexOf(item);
  1085. if (index < 0)
  1086. return null;
  1087. return View(index, 1);
  1088. }
  1089. /// <summary>
  1090. /// Create a list view on this list containing the last occurrence of a particular item.
  1091. /// <para>Returns <code>null</code> if the item is not in this list.</para>
  1092. /// </summary>
  1093. /// <param name="item">The item to find.</param>
  1094. /// <returns>The new list view.</returns>
  1095. [Tested]
  1096. public virtual IList<T> LastViewOf(T item)
  1097. {
  1098. int index = lastIndexOf(item);
  1099. if (index < 0)
  1100. return null;
  1101. return View(index, 1);
  1102. }
  1103. /// <summary>
  1104. /// Null if this list is not a view.
  1105. /// </summary>
  1106. /// <value>Underlying list for view.</value>
  1107. [Tested]
  1108. public virtual IList<T> Underlying { [Tested]get { return underlying; } }
  1109. /// <summary>
  1110. /// </summary>
  1111. /// <value>Offset for this list view or 0 for an underlying list.</value>
  1112. [Tested]
  1113. public virtual int Offset { [Tested]get { return offset; } }
  1114. /// <summary>
  1115. ///
  1116. /// </summary>
  1117. /// <value></value>
  1118. public virtual bool IsValid { get { return isValid; } }
  1119. /// <summary>
  1120. /// Slide this list view along the underlying list.
  1121. /// </summary>
  1122. /// <exception cref="NotAViewException"> if this list is not a view.</exception>
  1123. /// <exception cref="ArgumentOutOfRangeException"> if the operation
  1124. /// would bring either end of the view outside the underlying list.</exception>
  1125. /// <param name="offset">The signed amount to slide: positive to slide
  1126. /// towards the end.</param>
  1127. [Tested]
  1128. public virtual IList<T> Slide(int offset)
  1129. {
  1130. if (!TrySlide(offset, size))
  1131. throw new ArgumentOutOfRangeException();
  1132. return this;
  1133. }
  1134. /// <summary>
  1135. /// Slide this list view along the underlying list, changing its size.
  1136. /// </summary>
  1137. /// <exception cref="NotAViewException"> if this list is not a view.</exception>
  1138. /// <exception cref="ArgumentOutOfRangeException"> if the operation
  1139. /// would bring either end of the view outside the underlying list.</exception>
  1140. /// <param name="offset">The signed amount to slide: positive to slide
  1141. /// towards the end.</param>
  1142. /// <param name="size">The new size of the view.</param>
  1143. [Tested]
  1144. public virtual IList<T> Slide(int offset, int size)
  1145. {
  1146. if (!TrySlide(offset, size))
  1147. throw new ArgumentOutOfRangeException();
  1148. return this;
  1149. }
  1150. /// <summary>
  1151. ///
  1152. /// </summary>
  1153. /// <exception cref="NotAViewException"> if this list is not a view.</exception>
  1154. /// <param name="offset"></param>
  1155. /// <returns></returns>
  1156. [Tested]
  1157. public virtual bool TrySlide(int offset)
  1158. {
  1159. return TrySlide(offset, size);
  1160. }
  1161. /// <summary>
  1162. ///
  1163. /// </summary>
  1164. /// <exception cref="NotAViewException"> if this list is not a view.</exception>
  1165. /// <param name="offset"></param>
  1166. /// <param name="size"></param>
  1167. /// <returns></returns>
  1168. [Tested]
  1169. public virtual bool TrySlide(int offset, int size)
  1170. {
  1171. updatecheck();
  1172. if (underlying == null)
  1173. throw new NotAViewException("Not a view");
  1174. int newoffset = this.offset + offset;
  1175. int newsize = size;
  1176. if (newoffset < 0 || newsize < 0 || newoffset + newsize > underlyingsize)
  1177. return false;
  1178. this.offset = newoffset;
  1179. this.size = newsize;
  1180. return true;
  1181. }
  1182. /// <summary>
  1183. ///
  1184. /// <para>Returns null if <code>otherView</code> is strictly to the left of this view</para>
  1185. /// </summary>
  1186. /// <param name="otherView"></param>
  1187. /// <exception cref="IncompatibleViewException">If otherView does not have the same underlying list as this</exception>
  1188. /// <returns></returns>
  1189. public virtual IList<T> Span(IList<T> otherView)
  1190. {
  1191. if ((otherView == null) || ((otherView.Underlying ?? otherView) != (underlying ?? this)))
  1192. throw new IncompatibleViewException();
  1193. if (otherView.Offset + otherView.Count - Offset < 0)
  1194. return null;
  1195. return (underlying ?? this).View(Offset, otherView.Offset + otherView.Count - Offset);
  1196. }
  1197. /// <summary>
  1198. /// Reverst the list so the items are in the opposite sequence order.
  1199. /// </summary>
  1200. [Tested]
  1201. public virtual void Reverse()
  1202. {
  1203. updatecheck();
  1204. if (size == 0)
  1205. return;
  1206. for (int i = 0, length = size / 2, end = offset + size - 1; i < length; i++)
  1207. {
  1208. T swap = array[offset + i];
  1209. array[offset + i] = array[end - i];
  1210. array[end - i] = swap;
  1211. }
  1212. #if HASHINDEX
  1213. reindex(offset, offset + size);
  1214. #endif
  1215. //TODO: be more forgiving wrt. disposing
  1216. disposeOverlappingViews(true);
  1217. (underlying ?? this).raiseCollectionChanged();
  1218. }
  1219. /// <summary>
  1220. /// Check if this list is sorted according to the default sorting order
  1221. /// for the item type T, as defined by the <see cref="T:C5.Comparer`1"/> class
  1222. /// </summary>
  1223. /// <exception cref="NotComparableException">if T is not comparable</exception>
  1224. /// <returns>True if the list is sorted, else false.</returns>
  1225. [Tested]
  1226. public bool IsSorted() { return IsSorted(Comparer<T>.Default); }
  1227. /// <summary>
  1228. /// Check if this list is sorted according to a specific sorting order.
  1229. /// </summary>
  1230. /// <param name="c">The comparer defining the sorting order.</param>
  1231. /// <returns>True if the list is sorted, else false.</returns>
  1232. [Tested]
  1233. public virtual bool IsSorted(SCG.IComparer<T> c)
  1234. {
  1235. validitycheck();
  1236. for (int i = offset + 1, end = offset + size; i < end; i++)
  1237. if (c.Compare(array[i - 1], array[i]) > 0)
  1238. return false;
  1239. return true;
  1240. }
  1241. /// <summary>
  1242. /// Sort the items of the list according to the default sorting order
  1243. /// for the item type T, as defined by the Comparer[T] class
  1244. /// (<see cref="T:C5.Comparer`1"/>).
  1245. /// </summary>
  1246. /// <exception cref="InvalidOperationException">if T is not comparable</exception>
  1247. public virtual void Sort()
  1248. {
  1249. Sort(Comparer<T>.Default);
  1250. }
  1251. /// <summary>
  1252. /// Sort the items of the list according to a specific sorting order.
  1253. /// </summary>
  1254. /// <param name="comparer">The comparer defining the sorting order.</param>
  1255. [Tested]
  1256. public virtual void Sort(SCG.IComparer<T> comparer)
  1257. {
  1258. updatecheck();
  1259. if (size == 0)
  1260. return;
  1261. Sorting.IntroSort<T>(array, offset, size, comparer);
  1262. disposeOverlappingViews(false);
  1263. #if HASHINDEX
  1264. reindex(offset, offset + size);
  1265. #endif
  1266. (underlying ?? this).raiseCollectionChanged();
  1267. }
  1268. /// <summary>
  1269. /// Randomly shuffle the items of this list.
  1270. /// </summary>
  1271. public virtual void Shuffle() { Shuffle(new C5Random()); }
  1272. /// <summary>
  1273. /// Shuffle the items of this list according to a specific random source.
  1274. /// </summary>
  1275. /// <param name="rnd">The random source.</param>
  1276. public virtual void Shuffle(Random rnd)
  1277. {
  1278. updatecheck();
  1279. if (size == 0)
  1280. return;
  1281. for (int i = offset, top = offset + size, end = top - 1; i < end; i++)
  1282. {
  1283. int j = rnd.Next(i, top);
  1284. if (j != i)
  1285. {
  1286. T tmp = array[i];
  1287. array[i] = array[j];
  1288. array[j] = tmp;
  1289. }
  1290. }
  1291. disposeOverlappingViews(false);
  1292. #if HASHINDEX
  1293. reindex(offset, offset + size);
  1294. #endif
  1295. (underlying ?? this).raiseCollectionChanged();
  1296. }
  1297. #endregion
  1298. #region IIndexed<T> Members
  1299. /// <summary>
  1300. /// Search for an item in the list going forwrds from the start.
  1301. /// </summary>
  1302. /// <param name="item">Item to search for.</param>
  1303. /// <returns>Index of item from start.</returns>
  1304. [Tested]
  1305. public virtual int IndexOf(T item) { validitycheck(); return indexOf(item); }
  1306. /// <summary>
  1307. /// Search for an item in the list going backwords from the end.
  1308. /// </summary>
  1309. /// <param name="item">Item to search for.</param>
  1310. /// <returns>Index of item from the end.</returns>
  1311. [Tested]
  1312. public virtual int LastIndexOf(T item) { validitycheck(); return lastIndexOf(item); }
  1313. /// <summary>
  1314. /// Remove the item at a specific position of the list.
  1315. /// </summary>
  1316. /// <exception cref="IndexOutOfRangeException"> if index is negative or
  1317. /// &gt;= the size of the collection.</exception>
  1318. /// <param name="index">The index of the item to remove.</param>
  1319. /// <returns>The removed item.</returns>
  1320. [Tested]
  1321. public virtual T RemoveAt(int index)
  1322. {
  1323. updatecheck();
  1324. if (index < 0 || index >= size)
  1325. throw new IndexOutOfRangeException("Index out of range for sequenced collection");
  1326. T item = removeAt(index);
  1327. (underlying ?? this).raiseForRemoveAt(offset + index, item);
  1328. return item;
  1329. }
  1330. /// <summary>
  1331. /// Remove all items in an index interval.
  1332. /// </summary>
  1333. /// <exception cref="ArgumentOutOfRangeException">If <code>start</code>
  1334. /// and <code>count</code> does not describe a valid interval in the list</exception>
  1335. /// <param name="start">The index of the first item to remove.</param>
  1336. /// <param name="count">The number of items to remove.</param>
  1337. [Tested]
  1338. public virtual void RemoveInterval(int start, int count)
  1339. {
  1340. updatecheck();
  1341. if (count == 0)
  1342. return;
  1343. checkRange(start, count);
  1344. start += offset;
  1345. fixViewsBeforeRemove(start, count);
  1346. #if HASHINDEX
  1347. KeyValuePair<T, int> p = new KeyValuePair<T, int>();
  1348. for (int i = start, end = start + count; i < end; i++)
  1349. {
  1350. p.Key = array[i];
  1351. itemIndex.Remove(p);
  1352. }
  1353. #endif
  1354. Array.Copy(array, start + count, array, start, underlyingsize - start - count);
  1355. addtosize(-count);
  1356. Array.Clear(array, underlyingsize, count);
  1357. #if HASHINDEX
  1358. reindex(start);
  1359. #endif
  1360. (underlying ?? this).raiseForRemoveInterval(start, count);
  1361. }
  1362. void raiseForRemoveInterval(int start, int count)
  1363. {
  1364. if (ActiveEvents != 0)
  1365. {
  1366. raiseCollectionCleared(size == 0, count, start);
  1367. raiseCollectionChanged();
  1368. }
  1369. }
  1370. #endregion
  1371. #region ICollection<T> Members
  1372. /// <summary>
  1373. /// The value is symbolic indicating the type of asymptotic complexity
  1374. /// in terms of the size of this collection (worst-case or amortized as
  1375. /// relevant).
  1376. /// </summary>
  1377. /// <value>Speed.Linear</value>
  1378. [Tested]
  1379. public virtual Speed ContainsSpeed
  1380. {
  1381. [Tested]
  1382. get
  1383. {
  1384. #if HASHINDEX
  1385. return Speed.Constant;
  1386. #else
  1387. return Speed.Linear;
  1388. #endif
  1389. }
  1390. }
  1391. /// <summary>
  1392. ///
  1393. /// </summary>
  1394. /// <returns></returns>
  1395. [Tested]
  1396. public override int GetUnsequencedHashCode()
  1397. { validitycheck(); return base.GetUnsequencedHashCode(); }
  1398. /// <summary>
  1399. ///
  1400. /// </summary>
  1401. /// <param name="that"></param>
  1402. /// <returns></returns>
  1403. [Tested]
  1404. public override bool UnsequencedEquals(ICollection<T> that)
  1405. { validitycheck(); return base.UnsequencedEquals(that); }
  1406. /// <summary>
  1407. /// Check if this collection contains (an item equivalent to according to the
  1408. /// itemequalityComparer) a particular value.
  1409. /// </summary>
  1410. /// <param name="item">The value to check for.</param>
  1411. /// <returns>True if the items is in this collection.</returns>
  1412. [Tested]
  1413. public virtual bool Contains(T item)
  1414. { validitycheck(); return indexOf(item) >= 0; }
  1415. /// <summary>
  1416. /// Check if this collection contains an item equivalent according to the
  1417. /// itemequalityComparer to a particular value. If so, return in the ref argument (a
  1418. /// binary copy of) the actual value found.
  1419. /// </summary>
  1420. /// <param name="item">The value to look for…

Large files files are truncated, but you can click here to view the full file