/mono-2.10.8/mcs/class/System/System.Collections.Generic/SortedList.cs

# · C# · 1176 lines · 850 code · 230 blank · 96 comment · 181 complexity · 115f10de37f4cb8e8286a785065f990a MD5 · raw file

  1. //
  2. // System.Collections.Generic.SortedList.cs
  3. //
  4. // Author:
  5. // Sergey Chaban (serge@wildwestsoftware.com)
  6. // Duncan Mak (duncan@ximian.com)
  7. // Herve Poussineau (hpoussineau@fr.st
  8. // Zoltan Varga (vargaz@gmail.com)
  9. //
  10. //
  11. // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
  12. //
  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:
  20. //
  21. // The above copyright notice and this permission notice shall be
  22. // included in all copies or substantial portions of the Software.
  23. //
  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.
  31. //
  32. using System;
  33. using System.Collections;
  34. using System.Globalization;
  35. using System.Runtime.InteropServices;
  36. using System.Diagnostics;
  37. namespace System.Collections.Generic
  38. {
  39. /// <summary>
  40. /// Represents a collection of associated keys and values
  41. /// that are sorted by the keys and are accessible by key
  42. /// and by index.
  43. /// </summary>
  44. [Serializable]
  45. [ComVisible(false)]
  46. [DebuggerDisplay ("Count={Count}")]
  47. [DebuggerTypeProxy (typeof (CollectionDebuggerView<,>))]
  48. public class SortedList<TKey, TValue> : IDictionary<TKey, TValue>,
  49. IDictionary,
  50. ICollection,
  51. ICollection<KeyValuePair<TKey, TValue>>,
  52. IEnumerable<KeyValuePair<TKey, TValue>>,
  53. IEnumerable {
  54. private readonly static int INITIAL_SIZE = 16;
  55. private enum EnumeratorMode : int { KEY_MODE = 0, VALUE_MODE, ENTRY_MODE }
  56. private int inUse;
  57. private int modificationCount;
  58. private KeyValuePair<TKey, TValue>[] table;
  59. private IComparer<TKey> comparer;
  60. private int defaultCapacity;
  61. //
  62. // Constructors
  63. //
  64. public SortedList ()
  65. : this (INITIAL_SIZE, null)
  66. {
  67. }
  68. public SortedList (int capacity)
  69. : this (capacity, null)
  70. {
  71. }
  72. public SortedList (int capacity, IComparer<TKey> comparer)
  73. {
  74. if (capacity < 0)
  75. throw new ArgumentOutOfRangeException ("initialCapacity");
  76. if (capacity == 0)
  77. defaultCapacity = 0;
  78. else
  79. defaultCapacity = INITIAL_SIZE;
  80. Init (comparer, capacity, true);
  81. }
  82. public SortedList (IComparer<TKey> comparer) : this (INITIAL_SIZE, comparer)
  83. {
  84. }
  85. public SortedList (IDictionary<TKey, TValue> dictionary) : this (dictionary, null)
  86. {
  87. }
  88. public SortedList (IDictionary<TKey, TValue> dictionary, IComparer<TKey> comparer)
  89. {
  90. if (dictionary == null)
  91. throw new ArgumentNullException ("dictionary");
  92. Init (comparer, dictionary.Count, true);
  93. foreach (KeyValuePair<TKey, TValue> kvp in dictionary)
  94. Add (kvp.Key, kvp.Value);
  95. }
  96. //
  97. // Properties
  98. //
  99. // ICollection
  100. public int Count {
  101. get {
  102. return inUse;
  103. }
  104. }
  105. bool ICollection.IsSynchronized {
  106. get {
  107. return false;
  108. }
  109. }
  110. Object ICollection.SyncRoot {
  111. get {
  112. return this;
  113. }
  114. }
  115. // IDictionary
  116. bool IDictionary.IsFixedSize {
  117. get {
  118. return false;
  119. }
  120. }
  121. bool IDictionary.IsReadOnly {
  122. get {
  123. return false;
  124. }
  125. }
  126. public TValue this [TKey key] {
  127. get {
  128. if (key == null)
  129. throw new ArgumentNullException("key");
  130. int i = Find (key);
  131. if (i >= 0)
  132. return table [i].Value;
  133. else
  134. throw new KeyNotFoundException ();
  135. }
  136. set {
  137. if (key == null)
  138. throw new ArgumentNullException("key");
  139. PutImpl (key, value, true);
  140. }
  141. }
  142. object IDictionary.this [object key] {
  143. get {
  144. if (!(key is TKey))
  145. return null;
  146. else
  147. return this [(TKey)key];
  148. }
  149. set {
  150. this [ToKey (key)] = ToValue (value);
  151. }
  152. }
  153. public int Capacity {
  154. get {
  155. return table.Length;
  156. }
  157. set {
  158. int current = this.table.Length;
  159. if (inUse > value) {
  160. throw new ArgumentOutOfRangeException("capacity too small");
  161. }
  162. else if (value == 0) {
  163. // return to default size
  164. KeyValuePair<TKey, TValue> [] newTable = new KeyValuePair<TKey, TValue> [defaultCapacity];
  165. Array.Copy (table, newTable, inUse);
  166. this.table = newTable;
  167. }
  168. #if NET_1_0
  169. else if (current > defaultCapacity && value < current) {
  170. KeyValuePair<TKey, TValue> [] newTable = new KeyValuePair<TKey, TValue> [defaultCapacity];
  171. Array.Copy (table, newTable, inUse);
  172. this.table = newTable;
  173. }
  174. #endif
  175. else if (value > inUse) {
  176. KeyValuePair<TKey, TValue> [] newTable = new KeyValuePair<TKey, TValue> [value];
  177. Array.Copy (table, newTable, inUse);
  178. this.table = newTable;
  179. }
  180. else if (value > current) {
  181. KeyValuePair<TKey, TValue> [] newTable = new KeyValuePair<TKey, TValue> [value];
  182. Array.Copy (table, newTable, current);
  183. this.table = newTable;
  184. }
  185. }
  186. }
  187. public IList<TKey> Keys {
  188. get {
  189. return new ListKeys (this);
  190. }
  191. }
  192. public IList<TValue> Values {
  193. get {
  194. return new ListValues (this);
  195. }
  196. }
  197. ICollection IDictionary.Keys {
  198. get {
  199. return new ListKeys (this);
  200. }
  201. }
  202. ICollection IDictionary.Values {
  203. get {
  204. return new ListValues (this);
  205. }
  206. }
  207. ICollection<TKey> IDictionary<TKey, TValue>.Keys {
  208. get {
  209. return Keys;
  210. }
  211. }
  212. ICollection<TValue> IDictionary<TKey, TValue>.Values {
  213. get {
  214. return Values;
  215. }
  216. }
  217. public IComparer<TKey> Comparer {
  218. get {
  219. return comparer;
  220. }
  221. }
  222. bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly {
  223. get {
  224. return false;
  225. }
  226. }
  227. //
  228. // Public instance methods.
  229. //
  230. public void Add (TKey key, TValue value)
  231. {
  232. if (key == null)
  233. throw new ArgumentNullException ("key");
  234. PutImpl (key, value, false);
  235. }
  236. public bool ContainsKey (TKey key)
  237. {
  238. if (key == null)
  239. throw new ArgumentNullException ("key");
  240. return (Find (key) >= 0);
  241. }
  242. public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator ()
  243. {
  244. for (int i = 0; i < inUse; i ++) {
  245. KeyValuePair<TKey, TValue> current = this.table [i];
  246. yield return new KeyValuePair<TKey, TValue> (current.Key, current.Value);
  247. }
  248. }
  249. public bool Remove (TKey key)
  250. {
  251. if (key == null)
  252. throw new ArgumentNullException ("key");
  253. int i = IndexOfKey (key);
  254. if (i >= 0) {
  255. RemoveAt (i);
  256. return true;
  257. }
  258. else
  259. return false;
  260. }
  261. // ICollection<KeyValuePair<TKey, TValue>>
  262. void ICollection<KeyValuePair<TKey, TValue>>.Clear ()
  263. {
  264. defaultCapacity = INITIAL_SIZE;
  265. this.table = new KeyValuePair<TKey, TValue> [defaultCapacity];
  266. inUse = 0;
  267. modificationCount++;
  268. }
  269. public void Clear ()
  270. {
  271. defaultCapacity = INITIAL_SIZE;
  272. this.table = new KeyValuePair<TKey, TValue> [defaultCapacity];
  273. inUse = 0;
  274. modificationCount++;
  275. }
  276. void ICollection<KeyValuePair<TKey, TValue>>.CopyTo (KeyValuePair<TKey, TValue>[] array, int arrayIndex)
  277. {
  278. if (Count == 0)
  279. return;
  280. if (null == array)
  281. throw new ArgumentNullException();
  282. if (arrayIndex < 0)
  283. throw new ArgumentOutOfRangeException();
  284. if (arrayIndex >= array.Length)
  285. throw new ArgumentNullException("arrayIndex is greater than or equal to array.Length");
  286. if (Count > (array.Length - arrayIndex))
  287. throw new ArgumentNullException("Not enough space in array from arrayIndex to end of array");
  288. int i = arrayIndex;
  289. foreach (KeyValuePair<TKey, TValue> pair in this)
  290. array [i++] = pair;
  291. }
  292. void ICollection<KeyValuePair<TKey, TValue>>.Add (KeyValuePair<TKey, TValue> keyValuePair) {
  293. Add (keyValuePair.Key, keyValuePair.Value);
  294. }
  295. bool ICollection<KeyValuePair<TKey, TValue>>.Contains (KeyValuePair<TKey, TValue> keyValuePair) {
  296. int i = Find (keyValuePair.Key);
  297. if (i >= 0)
  298. return Comparer<KeyValuePair<TKey, TValue>>.Default.Compare (table [i], keyValuePair) == 0;
  299. else
  300. return false;
  301. }
  302. bool ICollection<KeyValuePair<TKey, TValue>>.Remove (KeyValuePair<TKey, TValue> keyValuePair) {
  303. int i = Find (keyValuePair.Key);
  304. if (i >= 0 && (Comparer<KeyValuePair<TKey, TValue>>.Default.Compare (table [i], keyValuePair) == 0)) {
  305. RemoveAt (i);
  306. return true;
  307. }
  308. else
  309. return false;
  310. }
  311. // IEnumerable<KeyValuePair<TKey, TValue>>
  312. IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator ()
  313. {
  314. for (int i = 0; i < inUse; i ++) {
  315. KeyValuePair<TKey, TValue> current = this.table [i];
  316. yield return new KeyValuePair<TKey, TValue> (current.Key, current.Value);
  317. }
  318. }
  319. // IEnumerable
  320. IEnumerator IEnumerable.GetEnumerator ()
  321. {
  322. return GetEnumerator ();
  323. }
  324. // IDictionary
  325. void IDictionary.Add (object key, object value)
  326. {
  327. PutImpl (ToKey (key), ToValue (value), false);
  328. }
  329. bool IDictionary.Contains (object key)
  330. {
  331. if (null == key)
  332. throw new ArgumentNullException();
  333. if (!(key is TKey))
  334. return false;
  335. return (Find ((TKey)key) >= 0);
  336. }
  337. IDictionaryEnumerator IDictionary.GetEnumerator ()
  338. {
  339. return new Enumerator (this, EnumeratorMode.ENTRY_MODE);
  340. }
  341. void IDictionary.Remove (object key)
  342. {
  343. if (null == key)
  344. throw new ArgumentNullException ("key");
  345. if (!(key is TKey))
  346. return;
  347. int i = IndexOfKey ((TKey)key);
  348. if (i >= 0) RemoveAt (i);
  349. }
  350. // ICollection
  351. void ICollection.CopyTo (Array array, int arrayIndex)
  352. {
  353. if (Count == 0)
  354. return;
  355. if (null == array)
  356. throw new ArgumentNullException();
  357. if (arrayIndex < 0)
  358. throw new ArgumentOutOfRangeException();
  359. if (array.Rank > 1)
  360. throw new ArgumentException("array is multi-dimensional");
  361. if (arrayIndex >= array.Length)
  362. throw new ArgumentNullException("arrayIndex is greater than or equal to array.Length");
  363. if (Count > (array.Length - arrayIndex))
  364. throw new ArgumentNullException("Not enough space in array from arrayIndex to end of array");
  365. IEnumerator<KeyValuePair<TKey,TValue>> it = GetEnumerator ();
  366. int i = arrayIndex;
  367. while (it.MoveNext ()) {
  368. array.SetValue (it.Current, i++);
  369. }
  370. }
  371. //
  372. // SortedList<TKey, TValue>
  373. //
  374. public void RemoveAt (int index)
  375. {
  376. KeyValuePair<TKey, TValue> [] table = this.table;
  377. int cnt = Count;
  378. if (index >= 0 && index < cnt) {
  379. if (index != cnt - 1) {
  380. Array.Copy (table, index+1, table, index, cnt-1-index);
  381. } else {
  382. table [index] = default (KeyValuePair <TKey, TValue>);
  383. }
  384. --inUse;
  385. ++modificationCount;
  386. } else {
  387. throw new ArgumentOutOfRangeException("index out of range");
  388. }
  389. }
  390. public int IndexOfKey (TKey key)
  391. {
  392. if (key == null)
  393. throw new ArgumentNullException ("key");
  394. int indx = 0;
  395. try {
  396. indx = Find (key);
  397. } catch (Exception) {
  398. throw new InvalidOperationException();
  399. }
  400. return (indx | (indx >> 31));
  401. }
  402. public int IndexOfValue (TValue value)
  403. {
  404. if (inUse == 0)
  405. return -1;
  406. for (int i = 0; i < inUse; i ++) {
  407. KeyValuePair<TKey, TValue> current = this.table [i];
  408. if (Equals (value, current.Value))
  409. return i;
  410. }
  411. return -1;
  412. }
  413. public bool ContainsValue (TValue value)
  414. {
  415. return IndexOfValue (value) >= 0;
  416. }
  417. public void TrimExcess ()
  418. {
  419. if (inUse < table.Length * 0.9)
  420. Capacity = inUse;
  421. }
  422. public bool TryGetValue (TKey key, out TValue value)
  423. {
  424. if (key == null)
  425. throw new ArgumentNullException("key");
  426. int i = Find (key);
  427. if (i >= 0) {
  428. value = table [i].Value;
  429. return true;
  430. }
  431. else {
  432. value = default (TValue);
  433. return false;
  434. }
  435. }
  436. //
  437. // Private methods
  438. //
  439. private void EnsureCapacity (int n, int free)
  440. {
  441. KeyValuePair<TKey, TValue> [] table = this.table;
  442. KeyValuePair<TKey, TValue> [] newTable = null;
  443. int cap = Capacity;
  444. bool gap = (free >=0 && free < Count);
  445. if (n > cap) {
  446. newTable = new KeyValuePair<TKey, TValue> [n << 1];
  447. }
  448. if (newTable != null) {
  449. if (gap) {
  450. int copyLen = free;
  451. if (copyLen > 0) {
  452. Array.Copy (table, 0, newTable, 0, copyLen);
  453. }
  454. copyLen = Count - free;
  455. if (copyLen > 0) {
  456. Array.Copy (table, free, newTable, free+1, copyLen);
  457. }
  458. } else {
  459. // Just a resizing, copy the entire table.
  460. Array.Copy (table, newTable, Count);
  461. }
  462. this.table = newTable;
  463. } else if (gap) {
  464. Array.Copy (table, free, table, free+1, Count - free);
  465. }
  466. }
  467. private void PutImpl (TKey key, TValue value, bool overwrite)
  468. {
  469. if (key == null)
  470. throw new ArgumentNullException ("null key");
  471. KeyValuePair<TKey, TValue> [] table = this.table;
  472. int freeIndx = -1;
  473. try {
  474. freeIndx = Find (key);
  475. } catch (Exception) {
  476. throw new InvalidOperationException();
  477. }
  478. if (freeIndx >= 0) {
  479. if (!overwrite)
  480. throw new ArgumentException("element already exists");
  481. table [freeIndx] = new KeyValuePair <TKey, TValue> (key, value);
  482. ++modificationCount;
  483. return;
  484. }
  485. freeIndx = ~freeIndx;
  486. if (freeIndx > Capacity + 1)
  487. throw new Exception ("SortedList::internal error ("+key+", "+value+") at ["+freeIndx+"]");
  488. EnsureCapacity (Count+1, freeIndx);
  489. table = this.table;
  490. table [freeIndx] = new KeyValuePair <TKey, TValue> (key, value);
  491. ++inUse;
  492. ++modificationCount;
  493. }
  494. private void Init (IComparer<TKey> comparer, int capacity, bool forceSize)
  495. {
  496. if (comparer == null)
  497. comparer = Comparer<TKey>.Default;
  498. this.comparer = comparer;
  499. if (!forceSize && (capacity < defaultCapacity))
  500. capacity = defaultCapacity;
  501. this.table = new KeyValuePair<TKey, TValue> [capacity];
  502. this.inUse = 0;
  503. this.modificationCount = 0;
  504. }
  505. private void CopyToArray (Array arr, int i,
  506. EnumeratorMode mode)
  507. {
  508. if (arr == null)
  509. throw new ArgumentNullException ("arr");
  510. if (i < 0 || i + this.Count > arr.Length)
  511. throw new ArgumentOutOfRangeException ("i");
  512. IEnumerator it = new Enumerator (this, mode);
  513. while (it.MoveNext ()) {
  514. arr.SetValue (it.Current, i++);
  515. }
  516. }
  517. private int Find (TKey key)
  518. {
  519. KeyValuePair<TKey, TValue> [] table = this.table;
  520. int len = Count;
  521. if (len == 0) return ~0;
  522. int left = 0;
  523. int right = len-1;
  524. while (left <= right) {
  525. int guess = (left + right) >> 1;
  526. int cmp = comparer.Compare (table[guess].Key, key);
  527. if (cmp == 0) return guess;
  528. if (cmp < 0) left = guess+1;
  529. else right = guess-1;
  530. }
  531. return ~left;
  532. }
  533. private TKey ToKey (object key) {
  534. if (key == null)
  535. throw new ArgumentNullException ("key");
  536. if (!(key is TKey))
  537. throw new ArgumentException ("The value \"" + key + "\" isn't of type \"" + typeof (TKey) + "\" and can't be used in this generic collection.", "key");
  538. return (TKey)key;
  539. }
  540. private TValue ToValue (object value) {
  541. if (!(value is TValue))
  542. throw new ArgumentException ("The value \"" + value + "\" isn't of type \"" + typeof (TValue) + "\" and can't be used in this generic collection.", "value");
  543. return (TValue)value;
  544. }
  545. internal TKey KeyAt (int index) {
  546. if (index >= 0 && index < Count)
  547. return table [index].Key;
  548. else
  549. throw new ArgumentOutOfRangeException("Index out of range");
  550. }
  551. internal TValue ValueAt (int index) {
  552. if (index >= 0 && index < Count)
  553. return table [index].Value;
  554. else
  555. throw new ArgumentOutOfRangeException("Index out of range");
  556. }
  557. //
  558. // Inner classes
  559. //
  560. private sealed class Enumerator : ICloneable, IDictionaryEnumerator, IEnumerator {
  561. private SortedList<TKey, TValue>host;
  562. private int stamp;
  563. private int pos;
  564. private int size;
  565. private EnumeratorMode mode;
  566. private object currentKey;
  567. private object currentValue;
  568. bool invalid = false;
  569. private readonly static string xstr = "SortedList.Enumerator: snapshot out of sync.";
  570. public Enumerator (SortedList<TKey, TValue>host, EnumeratorMode mode)
  571. {
  572. this.host = host;
  573. stamp = host.modificationCount;
  574. size = host.Count;
  575. this.mode = mode;
  576. Reset ();
  577. }
  578. public Enumerator (SortedList<TKey, TValue>host)
  579. : this (host, EnumeratorMode.ENTRY_MODE)
  580. {
  581. }
  582. public void Reset ()
  583. {
  584. if (host.modificationCount != stamp || invalid)
  585. throw new InvalidOperationException (xstr);
  586. pos = -1;
  587. currentKey = null;
  588. currentValue = null;
  589. }
  590. public bool MoveNext ()
  591. {
  592. if (host.modificationCount != stamp || invalid)
  593. throw new InvalidOperationException (xstr);
  594. KeyValuePair<TKey, TValue> [] table = host.table;
  595. if (++pos < size) {
  596. KeyValuePair<TKey, TValue> entry = table [pos];
  597. currentKey = entry.Key;
  598. currentValue = entry.Value;
  599. return true;
  600. }
  601. currentKey = null;
  602. currentValue = null;
  603. return false;
  604. }
  605. public DictionaryEntry Entry
  606. {
  607. get {
  608. if (invalid || pos >= size || pos == -1)
  609. throw new InvalidOperationException (xstr);
  610. return new DictionaryEntry (currentKey,
  611. currentValue);
  612. }
  613. }
  614. public Object Key {
  615. get {
  616. if (invalid || pos >= size || pos == -1)
  617. throw new InvalidOperationException (xstr);
  618. return currentKey;
  619. }
  620. }
  621. public Object Value {
  622. get {
  623. if (invalid || pos >= size || pos == -1)
  624. throw new InvalidOperationException (xstr);
  625. return currentValue;
  626. }
  627. }
  628. public Object Current {
  629. get {
  630. if (invalid || pos >= size || pos == -1)
  631. throw new InvalidOperationException (xstr);
  632. switch (mode) {
  633. case EnumeratorMode.KEY_MODE:
  634. return currentKey;
  635. case EnumeratorMode.VALUE_MODE:
  636. return currentValue;
  637. case EnumeratorMode.ENTRY_MODE:
  638. return this.Entry;
  639. default:
  640. throw new NotSupportedException (mode + " is not a supported mode.");
  641. }
  642. }
  643. }
  644. // ICloneable
  645. public object Clone ()
  646. {
  647. Enumerator e = new Enumerator (host, mode);
  648. e.stamp = stamp;
  649. e.pos = pos;
  650. e.size = size;
  651. e.currentKey = currentKey;
  652. e.currentValue = currentValue;
  653. e.invalid = invalid;
  654. return e;
  655. }
  656. }
  657. [Serializable]
  658. struct KeyEnumerator : IEnumerator <TKey>, IDisposable {
  659. const int NOT_STARTED = -2;
  660. // this MUST be -1, because we depend on it in move next.
  661. // we just decr the size, so, 0 - 1 == FINISHED
  662. const int FINISHED = -1;
  663. SortedList <TKey, TValue> l;
  664. int idx;
  665. int ver;
  666. internal KeyEnumerator (SortedList<TKey, TValue> l)
  667. {
  668. this.l = l;
  669. idx = NOT_STARTED;
  670. ver = l.modificationCount;
  671. }
  672. public void Dispose ()
  673. {
  674. idx = NOT_STARTED;
  675. }
  676. public bool MoveNext ()
  677. {
  678. if (ver != l.modificationCount)
  679. throw new InvalidOperationException ("Collection was modified after the enumerator was instantiated.");
  680. if (idx == NOT_STARTED)
  681. idx = l.Count;
  682. return idx != FINISHED && -- idx != FINISHED;
  683. }
  684. public TKey Current {
  685. get {
  686. if (idx < 0)
  687. throw new InvalidOperationException ();
  688. return l.KeyAt (l.Count - 1 - idx);
  689. }
  690. }
  691. void IEnumerator.Reset ()
  692. {
  693. if (ver != l.modificationCount)
  694. throw new InvalidOperationException ("Collection was modified after the enumerator was instantiated.");
  695. idx = NOT_STARTED;
  696. }
  697. object IEnumerator.Current {
  698. get { return Current; }
  699. }
  700. }
  701. [Serializable]
  702. struct ValueEnumerator : IEnumerator <TValue>, IDisposable {
  703. const int NOT_STARTED = -2;
  704. // this MUST be -1, because we depend on it in move next.
  705. // we just decr the size, so, 0 - 1 == FINISHED
  706. const int FINISHED = -1;
  707. SortedList <TKey, TValue> l;
  708. int idx;
  709. int ver;
  710. internal ValueEnumerator (SortedList<TKey, TValue> l)
  711. {
  712. this.l = l;
  713. idx = NOT_STARTED;
  714. ver = l.modificationCount;
  715. }
  716. public void Dispose ()
  717. {
  718. idx = NOT_STARTED;
  719. }
  720. public bool MoveNext ()
  721. {
  722. if (ver != l.modificationCount)
  723. throw new InvalidOperationException ("Collection was modified after the enumerator was instantiated.");
  724. if (idx == NOT_STARTED)
  725. idx = l.Count;
  726. return idx != FINISHED && -- idx != FINISHED;
  727. }
  728. public TValue Current {
  729. get {
  730. if (idx < 0)
  731. throw new InvalidOperationException ();
  732. return l.ValueAt (l.Count - 1 - idx);
  733. }
  734. }
  735. void IEnumerator.Reset ()
  736. {
  737. if (ver != l.modificationCount)
  738. throw new InvalidOperationException ("Collection was modified after the enumerator was instantiated.");
  739. idx = NOT_STARTED;
  740. }
  741. object IEnumerator.Current {
  742. get { return Current; }
  743. }
  744. }
  745. private class ListKeys : IList<TKey>, ICollection, IEnumerable {
  746. private SortedList<TKey, TValue> host;
  747. public ListKeys (SortedList<TKey, TValue> host)
  748. {
  749. if (host == null)
  750. throw new ArgumentNullException ();
  751. this.host = host;
  752. }
  753. // ICollection<TKey>
  754. public virtual void Add (TKey item) {
  755. throw new NotSupportedException();
  756. }
  757. public virtual bool Remove (TKey key) {
  758. throw new NotSupportedException ();
  759. }
  760. public virtual void Clear () {
  761. throw new NotSupportedException();
  762. }
  763. public virtual void CopyTo (TKey[] array, int arrayIndex) {
  764. if (host.Count == 0)
  765. return;
  766. if (array == null)
  767. throw new ArgumentNullException ("array");
  768. if (arrayIndex < 0)
  769. throw new ArgumentOutOfRangeException();
  770. if (arrayIndex >= array.Length)
  771. throw new ArgumentOutOfRangeException ("arrayIndex is greater than or equal to array.Length");
  772. if (Count > (array.Length - arrayIndex))
  773. throw new ArgumentOutOfRangeException("Not enough space in array from arrayIndex to end of array");
  774. int j = arrayIndex;
  775. for (int i = 0; i < Count; ++i)
  776. array [j ++] = host.KeyAt (i);
  777. }
  778. public virtual bool Contains (TKey item) {
  779. return host.IndexOfKey (item) > -1;
  780. }
  781. //
  782. // IList<TKey>
  783. //
  784. public virtual int IndexOf (TKey item) {
  785. return host.IndexOfKey (item);
  786. }
  787. public virtual void Insert (int index, TKey item) {
  788. throw new NotSupportedException ();
  789. }
  790. public virtual void RemoveAt (int index) {
  791. throw new NotSupportedException ();
  792. }
  793. public virtual TKey this [int index] {
  794. get {
  795. return host.KeyAt (index);
  796. }
  797. set {
  798. throw new NotSupportedException("attempt to modify a key");
  799. }
  800. }
  801. //
  802. // IEnumerable<TKey>
  803. //
  804. public virtual IEnumerator<TKey> GetEnumerator ()
  805. {
  806. /* We couldn't use yield as it does not support Reset () */
  807. return new KeyEnumerator (host);
  808. }
  809. //
  810. // ICollection
  811. //
  812. public virtual int Count {
  813. get {
  814. return host.Count;
  815. }
  816. }
  817. public virtual bool IsSynchronized {
  818. get {
  819. return ((ICollection)host).IsSynchronized;
  820. }
  821. }
  822. public virtual bool IsReadOnly {
  823. get {
  824. return true;
  825. }
  826. }
  827. public virtual Object SyncRoot {
  828. get {
  829. return ((ICollection)host).SyncRoot;
  830. }
  831. }
  832. public virtual void CopyTo (Array array, int arrayIndex)
  833. {
  834. host.CopyToArray (array, arrayIndex, EnumeratorMode.KEY_MODE);
  835. }
  836. //
  837. // IEnumerable
  838. //
  839. IEnumerator IEnumerable.GetEnumerator ()
  840. {
  841. for (int i = 0; i < host.Count; ++i)
  842. yield return host.KeyAt (i);
  843. }
  844. }
  845. private class ListValues : IList<TValue>, ICollection, IEnumerable {
  846. private SortedList<TKey, TValue>host;
  847. public ListValues (SortedList<TKey, TValue>host)
  848. {
  849. if (host == null)
  850. throw new ArgumentNullException ();
  851. this.host = host;
  852. }
  853. // ICollection<TValue>
  854. public virtual void Add (TValue item) {
  855. throw new NotSupportedException();
  856. }
  857. public virtual bool Remove (TValue value) {
  858. throw new NotSupportedException ();
  859. }
  860. public virtual void Clear () {
  861. throw new NotSupportedException();
  862. }
  863. public virtual void CopyTo (TValue[] array, int arrayIndex) {
  864. if (host.Count == 0)
  865. return;
  866. if (array == null)
  867. throw new ArgumentNullException ("array");
  868. if (arrayIndex < 0)
  869. throw new ArgumentOutOfRangeException();
  870. if (arrayIndex >= array.Length)
  871. throw new ArgumentOutOfRangeException ("arrayIndex is greater than or equal to array.Length");
  872. if (Count > (array.Length - arrayIndex))
  873. throw new ArgumentOutOfRangeException("Not enough space in array from arrayIndex to end of array");
  874. int j = arrayIndex;
  875. for (int i = 0; i < Count; ++i)
  876. array [j ++] = host.ValueAt (i);
  877. }
  878. public virtual bool Contains (TValue item) {
  879. return host.IndexOfValue (item) > -1;
  880. }
  881. //
  882. // IList<TValue>
  883. //
  884. public virtual int IndexOf (TValue item) {
  885. return host.IndexOfValue (item);
  886. }
  887. public virtual void Insert (int index, TValue item) {
  888. throw new NotSupportedException ();
  889. }
  890. public virtual void RemoveAt (int index) {
  891. throw new NotSupportedException ();
  892. }
  893. public virtual TValue this [int index] {
  894. get {
  895. return host.ValueAt (index);
  896. }
  897. set {
  898. throw new NotSupportedException("attempt to modify a key");
  899. }
  900. }
  901. //
  902. // IEnumerable<TValue>
  903. //
  904. public virtual IEnumerator<TValue> GetEnumerator ()
  905. {
  906. /* We couldn't use yield as it does not support Reset () */
  907. return new ValueEnumerator (host);
  908. }
  909. //
  910. // ICollection
  911. //
  912. public virtual int Count {
  913. get {
  914. return host.Count;
  915. }
  916. }
  917. public virtual bool IsSynchronized {
  918. get {
  919. return ((ICollection)host).IsSynchronized;
  920. }
  921. }
  922. public virtual bool IsReadOnly {
  923. get {
  924. return true;
  925. }
  926. }
  927. public virtual Object SyncRoot {
  928. get {
  929. return ((ICollection)host).SyncRoot;
  930. }
  931. }
  932. public virtual void CopyTo (Array array, int arrayIndex)
  933. {
  934. host.CopyToArray (array, arrayIndex, EnumeratorMode.VALUE_MODE);
  935. }
  936. //
  937. // IEnumerable
  938. //
  939. IEnumerator IEnumerable.GetEnumerator ()
  940. {
  941. for (int i = 0; i < host.Count; ++i)
  942. yield return host.ValueAt (i);
  943. }
  944. }
  945. } // SortedList
  946. } // System.Collections.Generic