PageRenderTime 55ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Boo.Lang/GenericList.cs

https://github.com/boo/boo-lang
C# | 697 lines | 566 code | 106 blank | 25 comment | 63 complexity | 2d0d16a4326adb45f70b5592846adfff MD5 | raw file
Possible License(s): GPL-2.0
  1. #region license
  2. // Copyright (c) 2004, Rodrigo B. de Oliveira (rbo@acm.org)
  3. // All rights reserved.
  4. //
  5. // Redistribution and use in source and binary forms, with or without modification,
  6. // are permitted provided that the following conditions are met:
  7. //
  8. // * Redistributions of source code must retain the above copyright notice,
  9. // this list of conditions and the following disclaimer.
  10. // * Redistributions in binary form must reproduce the above copyright notice,
  11. // this list of conditions and the following disclaimer in the documentation
  12. // and/or other materials provided with the distribution.
  13. // * Neither the name of Rodrigo B. de Oliveira nor the names of its
  14. // contributors may be used to endorse or promote products derived from this
  15. // software without specific prior written permission.
  16. //
  17. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  18. // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  19. // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  20. // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
  21. // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  23. // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  24. // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  25. // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26. // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. #endregion
  28. using System;
  29. using Boo.Lang.Runtime;
  30. namespace Boo.Lang
  31. {
  32. using System.Collections;
  33. using System.Collections.Generic;
  34. [Serializable]
  35. public class List<T> : IList<T>, IList
  36. {
  37. private const int DefaultCapacity = 16;
  38. protected T[] _items;
  39. protected int _count;
  40. public List() : this(DefaultCapacity)
  41. {
  42. }
  43. public List(System.Collections.IEnumerable enumerable) : this()
  44. {
  45. Extend(enumerable);
  46. }
  47. public List(int initialCapacity)
  48. {
  49. if (initialCapacity < 0)
  50. {
  51. throw new ArgumentOutOfRangeException("initialCapacity");
  52. }
  53. _items = new T[initialCapacity];
  54. _count = 0;
  55. }
  56. public List(T[] items, bool takeOwnership)
  57. {
  58. if (null == items)
  59. {
  60. throw new ArgumentNullException("items");
  61. }
  62. if (takeOwnership)
  63. {
  64. _items = items;
  65. }
  66. else
  67. {
  68. _items = (T[])items.Clone();
  69. }
  70. _count = items.Length;
  71. }
  72. public static List<T> operator*(List<T> lhs, int count)
  73. {
  74. return lhs.Multiply(count);
  75. }
  76. public static List<T> operator*(int count, List<T> rhs)
  77. {
  78. return rhs.Multiply(count);
  79. }
  80. public static List<T> operator+(List<T> lhs, System.Collections.IEnumerable rhs)
  81. {
  82. List<T> result = lhs.NewConcreteList(lhs.ToArray(), true);
  83. result.Extend(rhs);
  84. return result;
  85. }
  86. public List<T> Multiply(int count)
  87. {
  88. if (count < 0)
  89. {
  90. throw new ArgumentOutOfRangeException("count");
  91. }
  92. T[] items = new T[_count*count];
  93. for (int i=0; i<count; ++i)
  94. {
  95. Array.Copy(_items, 0, items, i*_count, _count);
  96. }
  97. return NewConcreteList(items, true);
  98. }
  99. protected virtual List<T> NewConcreteList(T[] items, bool takeOwnership)
  100. {
  101. return new List<T>(items, takeOwnership);
  102. }
  103. public IEnumerable<T> Reversed
  104. {
  105. get
  106. {
  107. for (int i=_count-1; i>=0; --i)
  108. {
  109. yield return _items[i];
  110. }
  111. }
  112. }
  113. public int Count
  114. {
  115. get { return _count; }
  116. }
  117. void ICollection<T>.Add(T item)
  118. {
  119. Push(item);
  120. }
  121. System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
  122. {
  123. return ((IEnumerable<T>) this).GetEnumerator();
  124. }
  125. public IEnumerator<T> GetEnumerator()
  126. {
  127. int originalCount = _count;
  128. T[] originalItems = _items;
  129. for (int i = 0; i < _count; ++i)
  130. {
  131. if (originalCount != _count || originalItems != _items)
  132. {
  133. throw new InvalidOperationException(ResourceManager.GetString("ListWasModified"));
  134. }
  135. yield return _items[i];
  136. }
  137. }
  138. public void CopyTo(T[] target, int index)
  139. {
  140. Array.Copy(_items, 0, target, index, _count);
  141. }
  142. public bool IsSynchronized
  143. {
  144. get { return false; }
  145. }
  146. public object SyncRoot
  147. {
  148. get { return _items; }
  149. }
  150. public bool IsReadOnly
  151. {
  152. get { return false; }
  153. }
  154. public T this[int index]
  155. {
  156. get
  157. {
  158. return _items[CheckIndex(NormalizeIndex(index))];
  159. }
  160. set
  161. {
  162. _items[CheckIndex(NormalizeIndex(index))] = value;
  163. }
  164. }
  165. public List<T> Push(T item)
  166. {
  167. return Add(item);
  168. }
  169. public virtual List<T> Add(T item)
  170. {
  171. EnsureCapacity(_count+1);
  172. _items[_count] = item;
  173. ++_count;
  174. return this;
  175. }
  176. public List<T> AddUnique(T item)
  177. {
  178. if (!Contains(item))
  179. {
  180. Add(item);
  181. }
  182. return this;
  183. }
  184. public List<T> Extend(System.Collections.IEnumerable enumerable)
  185. {
  186. foreach (T item in enumerable)
  187. {
  188. Add(item);
  189. }
  190. return this;
  191. }
  192. public List<T> ExtendUnique(System.Collections.IEnumerable enumerable)
  193. {
  194. foreach (T item in enumerable)
  195. {
  196. AddUnique(item);
  197. }
  198. return this;
  199. }
  200. public List<T> Collect(System.Predicate<T> condition)
  201. {
  202. if (null == condition)
  203. {
  204. throw new ArgumentNullException("condition");
  205. }
  206. List<T> newList = NewConcreteList(new T[0], true);
  207. InnerCollect(newList, condition);
  208. return newList;
  209. }
  210. public List<T> Collect(List<T> target, System.Predicate<T> condition)
  211. {
  212. if (null == target)
  213. {
  214. throw new ArgumentNullException("target");
  215. }
  216. if (null == condition)
  217. {
  218. throw new ArgumentNullException("condition");
  219. }
  220. InnerCollect(target, condition);
  221. return target;
  222. }
  223. public T[] ToArray()
  224. {
  225. T[] target = new T[_count];
  226. CopyTo(target, 0);
  227. return target;
  228. }
  229. public T[] ToArray(T[] array)
  230. {
  231. CopyTo(array, 0);
  232. return array;
  233. }
  234. public List<T> Sort()
  235. {
  236. Array.Sort(_items, 0, _count, BooComparer.Default);
  237. return this;
  238. }
  239. public List<T> Sort(System.Collections.IComparer comparer)
  240. {
  241. Array.Sort(_items, 0, _count, comparer);
  242. return this;
  243. }
  244. class ComparisonComparer : IComparer<T>
  245. {
  246. private readonly Comparison<T> _comparison;
  247. public ComparisonComparer(Comparison<T> comparison)
  248. {
  249. _comparison = comparison;
  250. }
  251. #region IComparer<T> Members
  252. public int Compare(T x, T y)
  253. {
  254. return _comparison(x, y);
  255. }
  256. #endregion
  257. }
  258. public List<T> Sort(System.Comparison<T> comparison)
  259. {
  260. return Sort(new ComparisonComparer(comparison));
  261. }
  262. public List<T> Sort(System.Collections.Generic.IComparer<T> comparer)
  263. {
  264. Array.Sort(_items, 0, _count, comparer);
  265. return this;
  266. }
  267. private class ComparerImpl : System.Collections.IComparer
  268. {
  269. Comparer _comparer;
  270. public ComparerImpl(Comparer comparer)
  271. {
  272. _comparer = comparer;
  273. }
  274. public int Compare(object lhs, object rhs)
  275. {
  276. return _comparer(lhs, rhs);
  277. }
  278. }
  279. public List<T> Sort(Comparer comparer)
  280. {
  281. if (null == comparer)
  282. {
  283. throw new ArgumentNullException("comparer");
  284. }
  285. return Sort(new ComparerImpl(comparer));
  286. }
  287. override public string ToString()
  288. {
  289. return "[" + Join(", ") + "]";
  290. }
  291. public string Join(string separator)
  292. {
  293. return Builtins.join(this, separator);
  294. }
  295. override public int GetHashCode()
  296. {
  297. int hash = _count;
  298. for (int i=0; i<_count; ++i)
  299. {
  300. T item = _items[i];
  301. if (null != item)
  302. {
  303. hash ^= item.GetHashCode();
  304. }
  305. }
  306. return hash;
  307. }
  308. override public bool Equals(object other)
  309. {
  310. if (other == this) return true;
  311. List<T> rhs = other as List<T>;
  312. if (null == rhs) return false;
  313. if (_count != rhs.Count) return false;
  314. for (int i=0; i<_count; ++i)
  315. {
  316. if (!RuntimeServices.EqualityOperator(_items[i], rhs[i]))
  317. {
  318. return false;
  319. }
  320. }
  321. return true;
  322. }
  323. public void Clear()
  324. {
  325. for (int i=0; i<_count; ++i)
  326. {
  327. _items[i] = default(T);
  328. }
  329. _count = 0;
  330. }
  331. public List<T> GetRange(int begin)
  332. {
  333. return InnerGetRange(AdjustIndex(NormalizeIndex(begin)), _count);
  334. }
  335. public List<T> GetRange(int begin, int end)
  336. {
  337. return InnerGetRange(
  338. AdjustIndex(NormalizeIndex(begin)),
  339. AdjustIndex(NormalizeIndex(end)));
  340. }
  341. public bool Contains(T item)
  342. {
  343. return -1 != IndexOf(item);
  344. }
  345. public bool Contains(System.Predicate<T> condition)
  346. {
  347. return -1 != IndexOf(condition);
  348. }
  349. public bool Find(System.Predicate<T> condition, out T found)
  350. {
  351. int index = IndexOf(condition);
  352. if (-1 != index)
  353. {
  354. found = _items[index];
  355. return true;
  356. }
  357. found = default(T);
  358. return false;
  359. }
  360. public List<T> FindAll(System.Predicate<T> condition)
  361. {
  362. List<T> result = NewConcreteList(new T[0], true);
  363. foreach (T item in this)
  364. {
  365. if (condition(item)) result.Add(item);
  366. }
  367. return result;
  368. }
  369. public int IndexOf(System.Predicate<T> condition)
  370. {
  371. if (null == condition)
  372. {
  373. throw new ArgumentNullException("condition");
  374. }
  375. for (int i=0; i<_count; ++i)
  376. {
  377. if (condition(_items[i]))
  378. {
  379. return i;
  380. }
  381. }
  382. return -1;
  383. }
  384. public int IndexOf(T item)
  385. {
  386. for (int i=0; i<_count; ++i)
  387. {
  388. if (RuntimeServices.EqualityOperator(_items[i], item))
  389. {
  390. return i;
  391. }
  392. }
  393. return -1;
  394. }
  395. public List<T> Insert(int index, T item)
  396. {
  397. int actual = NormalizeIndex(index);
  398. EnsureCapacity(Math.Max(_count, actual) + 1);
  399. if (actual < _count)
  400. {
  401. Array.Copy(_items, actual, _items, actual+1, _count-actual);
  402. }
  403. _items[actual] = item;
  404. ++_count;
  405. return this;
  406. }
  407. public T Pop()
  408. {
  409. return Pop(-1);
  410. }
  411. public T Pop(int index)
  412. {
  413. int actualIndex = CheckIndex(NormalizeIndex(index));
  414. T item = _items[actualIndex];
  415. InnerRemoveAt(actualIndex);
  416. return item;
  417. }
  418. public List<T> PopRange(int begin)
  419. {
  420. int actualIndex = AdjustIndex(NormalizeIndex(begin));
  421. List<T> range = InnerGetRange(actualIndex, AdjustIndex(NormalizeIndex(_count)));
  422. for (int i=actualIndex; i<_count; ++i)
  423. {
  424. _items[i] = default(T);
  425. }
  426. _count = actualIndex;
  427. return range;
  428. }
  429. public List<T> RemoveAll(System.Predicate<T> match)
  430. {
  431. if (null == match) throw new ArgumentNullException("match");
  432. for (int i=0; i<_count; ++i)
  433. {
  434. if (match(_items[i])) InnerRemoveAt(i--);
  435. }
  436. return this;
  437. }
  438. public List<T> Remove(T item)
  439. {
  440. InnerRemove(item);
  441. return this;
  442. }
  443. public List<T> RemoveAt(int index)
  444. {
  445. InnerRemoveAt(CheckIndex(NormalizeIndex(index)));
  446. return this;
  447. }
  448. void IList<T>.Insert(int index, T item)
  449. {
  450. Insert(index, item);
  451. }
  452. void IList<T>.RemoveAt(int index)
  453. {
  454. InnerRemoveAt(CheckIndex(NormalizeIndex(index)));
  455. }
  456. bool ICollection<T>.Remove(T item)
  457. {
  458. return InnerRemove(item);
  459. }
  460. void EnsureCapacity(int minCapacity)
  461. {
  462. if (minCapacity > _items.Length)
  463. {
  464. T[] items = NewArray(minCapacity);
  465. Array.Copy(_items, 0, items, 0, _count);
  466. _items = items;
  467. }
  468. }
  469. T[] NewArray(int minCapacity)
  470. {
  471. int newLen = Math.Max(1, _items.Length)*2;
  472. return new T[Math.Max(newLen, minCapacity)];
  473. }
  474. void InnerRemoveAt(int index)
  475. {
  476. --_count;
  477. _items[index] = default(T);
  478. if (index != _count)
  479. {
  480. Array.Copy(_items, index+1, _items, index, _count-index);
  481. }
  482. }
  483. bool InnerRemove(T item)
  484. {
  485. int index = IndexOf(item);
  486. if (index != -1)
  487. {
  488. InnerRemoveAt(index);
  489. return true;
  490. }
  491. return false;
  492. }
  493. void InnerCollect(List<T> target, System.Predicate<T> condition)
  494. {
  495. for (int i=0; i<_count; ++i)
  496. {
  497. T item = _items[i];
  498. if (condition(item))
  499. {
  500. target.Add(item);
  501. }
  502. }
  503. }
  504. List<T> InnerGetRange(int begin, int end)
  505. {
  506. int targetLen = end-begin;
  507. if (targetLen > 0)
  508. {
  509. T[] target = new T[targetLen];
  510. Array.Copy(_items, begin, target, 0, targetLen);
  511. return NewConcreteList(target, true);
  512. }
  513. return NewConcreteList(new T[0], true);
  514. }
  515. int AdjustIndex(int index)
  516. {
  517. if (index > _count)
  518. {
  519. return _count;
  520. }
  521. if (index < 0)
  522. {
  523. return 0;
  524. }
  525. return index;
  526. }
  527. int CheckIndex(int index)
  528. {
  529. if (index >= _count)
  530. {
  531. throw new IndexOutOfRangeException();
  532. }
  533. return index;
  534. }
  535. int NormalizeIndex(int index)
  536. {
  537. if (index < 0)
  538. {
  539. index += _count;
  540. }
  541. return index;
  542. }
  543. #region IList Members
  544. int IList.Add(object value)
  545. {
  546. Add((T)value);
  547. return Count - 1;
  548. }
  549. void IList.Insert(int index, object value)
  550. {
  551. Insert(index, Coerce(value));
  552. }
  553. private static T Coerce(object value)
  554. {
  555. if (value is T) return (T) value;
  556. return (T)RuntimeServices.Coerce(value, typeof(T));
  557. }
  558. void IList.Remove(object value)
  559. {
  560. Remove(Coerce(value));
  561. }
  562. int IList.IndexOf(object value)
  563. {
  564. return IndexOf(Coerce(value));
  565. }
  566. bool IList.Contains(object value)
  567. {
  568. return Contains(Coerce(value));
  569. }
  570. object IList.this[int index]
  571. {
  572. get { return this[index]; }
  573. set { this[index] = Coerce(value); }
  574. }
  575. void IList.RemoveAt(int index)
  576. {
  577. RemoveAt(index);
  578. }
  579. bool IList.IsFixedSize
  580. {
  581. get { return false; }
  582. }
  583. #endregion
  584. #region ICollection Members
  585. void ICollection.CopyTo(Array array, int index)
  586. {
  587. Array.Copy(_items, 0, array, index, _count);
  588. }
  589. #endregion
  590. }
  591. }