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

/src/Boo.Lang/GenericList.cs

http://github.com/bamboo/boo
C# | 626 lines | 499 code | 102 blank | 25 comment | 65 complexity | 2447d47a16dddd33a0fe0994d19bba4f 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 System.Collections;
  30. using System.Collections.Generic;
  31. using Boo.Lang.Resources;
  32. using Boo.Lang.Runtime;
  33. namespace Boo.Lang
  34. {
  35. public delegate TResult Function<in T1, out TResult>(T1 arg);
  36. [Serializable]
  37. public class List<T> : IList<T>, IList, IEquatable<List<T>>
  38. {
  39. private static readonly T[] EmptyArray = new T[0];
  40. protected T[] _items;
  41. protected int _count;
  42. public List()
  43. {
  44. _items = EmptyArray;
  45. }
  46. public List(IEnumerable enumerable) : this()
  47. {
  48. Extend(enumerable);
  49. }
  50. public List(int initialCapacity)
  51. {
  52. if (initialCapacity < 0)
  53. throw new ArgumentOutOfRangeException("initialCapacity");
  54. _items = new T[initialCapacity];
  55. _count = 0;
  56. }
  57. public List(T[] items, bool takeOwnership)
  58. {
  59. if (null == items)
  60. throw new ArgumentNullException("items");
  61. _items = takeOwnership ? items : (T[]) items.Clone();
  62. _count = items.Length;
  63. }
  64. public static List<T> operator*(List<T> lhs, int count)
  65. {
  66. return lhs.Multiply(count);
  67. }
  68. public static List<T> operator*(int count, List<T> rhs)
  69. {
  70. return rhs.Multiply(count);
  71. }
  72. public static List<T> operator+(List<T> lhs, IEnumerable rhs)
  73. {
  74. var result = lhs.NewConcreteList(lhs.ToArray(), true);
  75. result.Extend(rhs);
  76. return result;
  77. }
  78. public List<T> Multiply(int count)
  79. {
  80. if (count < 0)
  81. throw new ArgumentOutOfRangeException("count");
  82. var items = new T[_count*count];
  83. for (int i=0; i<count; ++i)
  84. Array.Copy(_items, 0, items, i*_count, _count);
  85. return NewConcreteList(items, true);
  86. }
  87. protected virtual List<T> NewConcreteList(T[] items, bool takeOwnership)
  88. {
  89. return new List<T>(items, takeOwnership);
  90. }
  91. public IEnumerable<T> Reversed
  92. {
  93. get
  94. {
  95. for (int i=_count-1; i>=0; --i)
  96. yield return _items[i];
  97. }
  98. }
  99. public int Count
  100. {
  101. get { return _count; }
  102. }
  103. void ICollection<T>.Add(T item)
  104. {
  105. Push(item);
  106. }
  107. IEnumerator IEnumerable.GetEnumerator()
  108. {
  109. return ((IEnumerable<T>) this).GetEnumerator();
  110. }
  111. public IEnumerator<T> GetEnumerator()
  112. {
  113. int originalCount = _count;
  114. T[] originalItems = _items;
  115. for (int i = 0; i < _count; ++i)
  116. {
  117. if (originalCount != _count || originalItems != _items)
  118. throw new InvalidOperationException(StringResources.ListWasModified);
  119. yield return _items[i];
  120. }
  121. }
  122. public void CopyTo(T[] target, int index)
  123. {
  124. Array.Copy(_items, 0, target, index, _count);
  125. }
  126. public bool IsSynchronized
  127. {
  128. get { return false; }
  129. }
  130. public object SyncRoot
  131. {
  132. get { return _items; }
  133. }
  134. public bool IsReadOnly
  135. {
  136. get { return false; }
  137. }
  138. public T this[int index]
  139. {
  140. get { return _items[CheckIndex(NormalizeIndex(index))]; }
  141. set { _items[CheckIndex(NormalizeIndex(index))] = value; }
  142. }
  143. public T FastAt(int normalizedIndex)
  144. {
  145. return _items[normalizedIndex];
  146. }
  147. public List<T> Push(T item)
  148. {
  149. return Add(item);
  150. }
  151. public virtual List<T> Add(T item)
  152. {
  153. EnsureCapacity(_count+1);
  154. _items[_count] = item;
  155. ++_count;
  156. return this;
  157. }
  158. public List<T> AddUnique(T item)
  159. {
  160. if (!Contains(item))
  161. Add(item);
  162. return this;
  163. }
  164. public List<T> Extend(IEnumerable enumerable)
  165. {
  166. AddRange(enumerable);
  167. return this;
  168. }
  169. public void AddRange(IEnumerable enumerable)
  170. {
  171. foreach (T item in enumerable)
  172. Add(item);
  173. }
  174. public List<T> ExtendUnique(IEnumerable enumerable)
  175. {
  176. foreach (T item in enumerable)
  177. AddUnique(item);
  178. return this;
  179. }
  180. public List<T> Collect(Predicate<T> condition)
  181. {
  182. if (null == condition)
  183. throw new ArgumentNullException("condition");
  184. var newList = NewConcreteList(new T[0], true);
  185. InnerCollect(newList, condition);
  186. return newList;
  187. }
  188. public List<T> Collect(List<T> target, Predicate<T> condition)
  189. {
  190. if (null == target)
  191. throw new ArgumentNullException("target");
  192. if (null == condition)
  193. throw new ArgumentNullException("condition");
  194. InnerCollect(target, condition);
  195. return target;
  196. }
  197. public T[] ToArray()
  198. {
  199. if (_count == 0)
  200. return EmptyArray;
  201. var target = new T[_count];
  202. CopyTo(target, 0);
  203. return target;
  204. }
  205. public T[] ToArray(T[] array)
  206. {
  207. CopyTo(array, 0);
  208. return array;
  209. }
  210. public TOut[] ToArray<TOut>(Function<T, TOut> selector)
  211. {
  212. var result = new TOut[_count];
  213. for (var i = 0; i < _count; ++i)
  214. result[i] = selector(_items[i]);
  215. return result;
  216. }
  217. public List<T> Sort()
  218. {
  219. Array.Sort(_items, 0, _count, BooComparer.Default);
  220. return this;
  221. }
  222. public List<T> Sort(IComparer comparer)
  223. {
  224. Array.Sort(_items, 0, _count, comparer);
  225. return this;
  226. }
  227. private sealed class ComparisonComparer : IComparer<T>
  228. {
  229. private readonly Comparison<T> _comparison;
  230. public ComparisonComparer(Comparison<T> comparison)
  231. {
  232. _comparison = comparison;
  233. }
  234. #region IComparer<T> Members
  235. public int Compare(T x, T y)
  236. {
  237. return _comparison(x, y);
  238. }
  239. #endregion
  240. }
  241. public List<T> Sort(Comparison<T> comparison)
  242. {
  243. return Sort(new ComparisonComparer(comparison));
  244. }
  245. public List<T> Sort(IComparer<T> comparer)
  246. {
  247. Array.Sort(_items, 0, _count, comparer);
  248. return this;
  249. }
  250. public List<T> Sort(Comparer<T> comparer)
  251. {
  252. if (null == comparer)
  253. throw new ArgumentNullException("comparer");
  254. Array.Sort(_items, 0, _count, comparer);
  255. return this;
  256. }
  257. override public string ToString()
  258. {
  259. return "[" + Join(", ") + "]";
  260. }
  261. public string Join(string separator)
  262. {
  263. return Builtins.join(this, separator);
  264. }
  265. override public int GetHashCode()
  266. {
  267. var hash = _count;
  268. for (var i=0; i<_count; ++i)
  269. {
  270. var item = _items[i];
  271. if (item != null)
  272. hash ^= item.GetHashCode();
  273. }
  274. return hash;
  275. }
  276. override public bool Equals(object other)
  277. {
  278. return this == other || Equals(other as List<T>);
  279. }
  280. public bool Equals(List<T> other)
  281. {
  282. if (other == null) return false;
  283. if (ReferenceEquals(this, other)) return true;
  284. if (_count != other.Count) return false;
  285. for (var i=0; i < _count; ++i)
  286. if (!RuntimeServices.EqualityOperator(_items[i], other[i]))
  287. return false;
  288. return true;
  289. }
  290. public void Clear()
  291. {
  292. for (int i=0; i<_count; ++i)
  293. _items[i] = default(T);
  294. _count = 0;
  295. }
  296. public List<T> GetRange(int begin)
  297. {
  298. return InnerGetRange(AdjustIndex(NormalizeIndex(begin)), _count);
  299. }
  300. public List<T> GetRange(int begin, int end)
  301. {
  302. return InnerGetRange(
  303. AdjustIndex(NormalizeIndex(begin)),
  304. AdjustIndex(NormalizeIndex(end)));
  305. }
  306. public bool Contains(T item)
  307. {
  308. return -1 != IndexOf(item);
  309. }
  310. public bool Contains(Predicate<T> condition)
  311. {
  312. return -1 != IndexOf(condition);
  313. }
  314. public bool Find(Predicate<T> condition, out T found)
  315. {
  316. int index = IndexOf(condition);
  317. if (-1 != index)
  318. {
  319. found = _items[index];
  320. return true;
  321. }
  322. found = default(T);
  323. return false;
  324. }
  325. public List<T> FindAll(Predicate<T> condition)
  326. {
  327. var result = NewConcreteList(new T[0], true);
  328. foreach (T item in this)
  329. if (condition(item)) result.Add(item);
  330. return result;
  331. }
  332. public int IndexOf(Predicate<T> condition)
  333. {
  334. if (null == condition)
  335. throw new ArgumentNullException("condition");
  336. for (int i=0; i<_count; ++i)
  337. if (condition(_items[i]))
  338. return i;
  339. return -1;
  340. }
  341. public int IndexOf(T item)
  342. {
  343. for (int i=0; i<_count; ++i)
  344. if (RuntimeServices.EqualityOperator(_items[i], item))
  345. return i;
  346. return -1;
  347. }
  348. public List<T> Insert(int index, T item)
  349. {
  350. int actual = NormalizeIndex(index);
  351. EnsureCapacity(Math.Max(_count, actual) + 1);
  352. if (actual < _count)
  353. Array.Copy(_items, actual, _items, actual+1, _count-actual);
  354. _items[actual] = item;
  355. ++_count;
  356. return this;
  357. }
  358. public T Pop()
  359. {
  360. return Pop(-1);
  361. }
  362. public T Pop(int index)
  363. {
  364. int actualIndex = CheckIndex(NormalizeIndex(index));
  365. T item = _items[actualIndex];
  366. InnerRemoveAt(actualIndex);
  367. return item;
  368. }
  369. public List<T> PopRange(int begin)
  370. {
  371. int actualIndex = AdjustIndex(NormalizeIndex(begin));
  372. List<T> range = InnerGetRange(actualIndex, AdjustIndex(NormalizeIndex(_count)));
  373. for (int i=actualIndex; i<_count; ++i)
  374. _items[i] = default(T);
  375. _count = actualIndex;
  376. return range;
  377. }
  378. public List<T> RemoveAll(Predicate<T> match)
  379. {
  380. if (null == match) throw new ArgumentNullException("match");
  381. for (int i=0; i<_count; ++i)
  382. if (match(_items[i])) InnerRemoveAt(i--);
  383. return this;
  384. }
  385. public List<T> Remove(T item)
  386. {
  387. InnerRemove(item);
  388. return this;
  389. }
  390. public List<T> RemoveAt(int index)
  391. {
  392. InnerRemoveAt(CheckIndex(NormalizeIndex(index)));
  393. return this;
  394. }
  395. void IList<T>.Insert(int index, T item)
  396. {
  397. Insert(index, item);
  398. }
  399. void IList<T>.RemoveAt(int index)
  400. {
  401. InnerRemoveAt(CheckIndex(NormalizeIndex(index)));
  402. }
  403. bool ICollection<T>.Remove(T item)
  404. {
  405. return InnerRemove(item);
  406. }
  407. void EnsureCapacity(int minCapacity)
  408. {
  409. if (minCapacity > _items.Length)
  410. {
  411. T[] items = NewArray(minCapacity);
  412. Array.Copy(_items, 0, items, 0, _count);
  413. _items = items;
  414. }
  415. }
  416. T[] NewArray(int minCapacity)
  417. {
  418. int newLen = Math.Max(1, _items.Length)*2;
  419. return new T[Math.Max(newLen, minCapacity)];
  420. }
  421. void InnerRemoveAt(int index)
  422. {
  423. --_count;
  424. _items[index] = default(T);
  425. if (index != _count)
  426. Array.Copy(_items, index+1, _items, index, _count-index);
  427. }
  428. bool InnerRemove(T item)
  429. {
  430. int index = IndexOf(item);
  431. if (index != -1)
  432. {
  433. InnerRemoveAt(index);
  434. return true;
  435. }
  436. return false;
  437. }
  438. void InnerCollect(List<T> target, Predicate<T> condition)
  439. {
  440. for (int i=0; i<_count; ++i)
  441. {
  442. T item = _items[i];
  443. if (condition(item))
  444. target.Add(item);
  445. }
  446. }
  447. List<T> InnerGetRange(int begin, int end)
  448. {
  449. int targetLen = end-begin;
  450. if (targetLen > 0)
  451. {
  452. var target = new T[targetLen];
  453. Array.Copy(_items, begin, target, 0, targetLen);
  454. return NewConcreteList(target, true);
  455. }
  456. return NewConcreteList(new T[0], true);
  457. }
  458. int AdjustIndex(int index)
  459. {
  460. if (index > _count)
  461. return _count;
  462. if (index < 0)
  463. return 0;
  464. return index;
  465. }
  466. int CheckIndex(int index)
  467. {
  468. if (index >= _count)
  469. throw new IndexOutOfRangeException();
  470. return index;
  471. }
  472. int NormalizeIndex(int index)
  473. {
  474. return index < 0 ? index + _count : index;
  475. }
  476. #region IList Members
  477. int IList.Add(object value)
  478. {
  479. Add((T)value);
  480. return Count - 1;
  481. }
  482. void IList.Insert(int index, object value)
  483. {
  484. Insert(index, Coerce(value));
  485. }
  486. private static T Coerce(object value)
  487. {
  488. if (value is T) return (T) value;
  489. return (T)RuntimeServices.Coerce(value, typeof(T));
  490. }
  491. void IList.Remove(object value)
  492. {
  493. Remove(Coerce(value));
  494. }
  495. int IList.IndexOf(object value)
  496. {
  497. return IndexOf(Coerce(value));
  498. }
  499. bool IList.Contains(object value)
  500. {
  501. return Contains(Coerce(value));
  502. }
  503. object IList.this[int index]
  504. {
  505. get { return this[index]; }
  506. set { this[index] = Coerce(value); }
  507. }
  508. void IList.RemoveAt(int index)
  509. {
  510. RemoveAt(index);
  511. }
  512. bool IList.IsFixedSize
  513. {
  514. get { return false; }
  515. }
  516. #endregion
  517. #region ICollection Members
  518. void ICollection.CopyTo(Array array, int index)
  519. {
  520. Array.Copy(_items, 0, array, index, _count);
  521. }
  522. #endregion
  523. }
  524. }