PageRenderTime 48ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/CoolEngine/IronPython/Src/IronPython/Runtime/List.cs

#
C# | 1318 lines | 961 code | 256 blank | 101 comment | 167 complexity | 2a0b66261c86a16dbc7b76948b40f892 MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public License. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Microsoft Public License, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Microsoft Public License.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System;
  16. using System.Collections;
  17. using System.Collections.Generic;
  18. using System.Reflection;
  19. using System.Runtime.InteropServices;
  20. using System.Text;
  21. using System.Diagnostics;
  22. using System.Threading;
  23. using SpecialNameAttribute = System.Runtime.CompilerServices.SpecialNameAttribute;
  24. using IronPython.Compiler;
  25. using IronPython.Runtime.Types;
  26. using IronPython.Runtime.Calls;
  27. using IronPython.Runtime.Operations;
  28. using Microsoft.Scripting;
  29. using Microsoft.Scripting.Actions;
  30. using Microsoft.Scripting.Runtime;
  31. using Microsoft.Scripting.Utils;
  32. using Microsoft.Scripting.Math;
  33. namespace IronPython.Runtime {
  34. [PythonSystemType("list"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
  35. public class List : IMutableSequence, IList, ICodeFormattable, IValueEquality, IList<object> {
  36. internal int _size;
  37. internal volatile object[] _data;
  38. public void __init__() {
  39. _data = new object[8];
  40. _size = 0;
  41. }
  42. public void __init__([NotNull] IEnumerable enumerable) {
  43. __init__();
  44. foreach (object o in enumerable) {
  45. AddNoLock(o);
  46. }
  47. }
  48. public void __init__([NotNull] ICollection sequence) {
  49. if (this == sequence) {
  50. // list.__init__(l, l) resets l
  51. _size = 0;
  52. return;
  53. }
  54. _data = new object[sequence.Count];
  55. int i = 0;
  56. foreach (object item in sequence) {
  57. _data[i++] = item;
  58. }
  59. _size = i;
  60. }
  61. public void __init__([NotNull] string sequence) {
  62. _data = new object[sequence.Length];
  63. _size = sequence.Length;
  64. for (int i = 0; i < sequence.Length; i++) {
  65. _data[i] = RuntimeHelpers.CharToString(sequence[i]);
  66. }
  67. }
  68. public void __init__(CodeContext context, object sequence) {
  69. try {
  70. object len;
  71. if (PythonTypeOps.TryInvokeUnaryOperator(context, sequence, Symbols.Length, out len)) {
  72. int ilen = Converter.ConvertToInt32(len);
  73. _data = new object[ilen];
  74. _size = 0;
  75. extend(sequence);
  76. } else {
  77. _data = new object[20];
  78. _size = 0;
  79. extend(sequence);
  80. }
  81. } catch (MissingMemberException) {
  82. _data = new object[20];
  83. _size = 0;
  84. extend(sequence);
  85. }
  86. }
  87. private List(IEnumerator e)
  88. : this(10) {
  89. while (e.MoveNext()) AddNoLock(e.Current);
  90. }
  91. internal List(int capacity) {
  92. if (capacity == 0) {
  93. _data = ArrayUtils.EmptyObjects;
  94. } else {
  95. _data = new object[capacity];
  96. }
  97. }
  98. private List(params object[] items) {
  99. _data = items;
  100. _size = _data.Length;
  101. }
  102. public List()
  103. : this(0) {
  104. }
  105. #if ALLOC_DEBUG
  106. private static int total, totalSize, cnt, growthCnt, growthSize;
  107. ~List() {
  108. total += _data.Length;
  109. totalSize += _size;
  110. cnt++;
  111. Console.Error.WriteLine("List: allocated {0} used {1} total wasted {2} - grand total wasted {3}", _data.Length, _size, total-totalSize, growthSize + total - totalSize);
  112. Console.Error.WriteLine(" Growing {0} {1} avg {2}", growthCnt, growthSize, growthSize / growthCnt);
  113. }
  114. #endif
  115. internal List(object sequence) {
  116. ICollection items = sequence as ICollection;
  117. object len;
  118. if (items != null) {
  119. _data = new object[items.Count];
  120. int i = 0;
  121. foreach (object item in items) {
  122. _data[i++] = item;
  123. }
  124. _size = i;
  125. } else if (PythonTypeOps.TryInvokeUnaryOperator(DefaultContext.Default,
  126. sequence,
  127. Symbols.Length,
  128. out len)) {
  129. int ilen = Converter.ConvertToInt32(len);
  130. _data = new object[ilen];
  131. extend(sequence);
  132. } else {
  133. _data = new object[20];
  134. extend(sequence);
  135. }
  136. }
  137. internal List(ICollection items)
  138. : this(items.Count) {
  139. int i = 0;
  140. foreach (object item in items) {
  141. _data[i++] = item;
  142. }
  143. _size = i;
  144. }
  145. /// <summary>
  146. /// Creates a new list with the data in the array and a size
  147. /// the same as the length of the array. The array is held
  148. /// onto and may be mutated in the future by the list.
  149. /// </summary>
  150. /// <param name="items"></param>
  151. internal static List FromArrayNoCopy(params object[] data) {
  152. return new List(data);
  153. }
  154. internal object[] GetObjectArray() {
  155. lock (this) {
  156. return ArrayOps.CopyArray(_data, _size);
  157. }
  158. }
  159. #region binary operators
  160. public static List operator +([NotNull]List l1, [NotNull]List l2) {
  161. object[] them = l2.GetObjectArray();
  162. lock (l1) {
  163. object[] ret = ArrayOps.CopyArray(l1._data, l1._size + them.Length);
  164. Array.Copy(them, 0, ret, l1._size, them.Length);
  165. return new List(ret);
  166. }
  167. }
  168. public static List operator *([NotNull]List l, int count) {
  169. return MultiplyWorker(l, count);
  170. }
  171. public static List operator *(int count, List l) {
  172. return MultiplyWorker(l, count);
  173. }
  174. public static object operator *([NotNull]List self, object count) {
  175. return PythonOps.MultiplySequence<List>(MultiplyWorker, self, count, true);
  176. }
  177. public static object operator *(object count, [NotNull]List self) {
  178. return PythonOps.MultiplySequence<List>(MultiplyWorker, self, count, false);
  179. }
  180. private static List MultiplyWorker(List self, int count) {
  181. if (count <= 0) return PythonOps.MakeEmptyList(0);
  182. int n, newCount;
  183. object[] ret;
  184. lock (self) {
  185. n = self._size;
  186. //??? is this useful optimization
  187. //???if (n == 1) return new List(Array.ArrayList.Repeat(this[0], count));
  188. newCount = n * count;
  189. ret = ArrayOps.CopyArray(self._data, newCount);
  190. }
  191. // this should be extremely fast for large count as it uses the same algoithim as efficient integer powers
  192. // ??? need to test to see how large count and n need to be for this to be fastest approach
  193. int block = n;
  194. int pos = n;
  195. while (pos < newCount) {
  196. Array.Copy(ret, 0, ret, pos, Math.Min(block, newCount - pos));
  197. pos += block;
  198. block *= 2;
  199. }
  200. return new List(ret);
  201. }
  202. #endregion
  203. public virtual int __len__() {
  204. return _size;
  205. }
  206. public virtual IEnumerator __iter__() {
  207. // return type is strongly typed to IEnumerator so that
  208. // we can call it w/o requiring an explicit conversion. If the
  209. // user overrides this we'll place a conversion in the wrapper
  210. // helper
  211. return new listiterator(this);
  212. }
  213. public virtual bool __contains__(object value) {
  214. lock (this) {
  215. for (int i = 0; i < _size; i++) {
  216. object thisIndex = _data[i];
  217. // release the lock while we may call user code...
  218. Monitor.Exit(this);
  219. try {
  220. if (PythonOps.EqualRetBool(thisIndex, value))
  221. return true;
  222. } finally {
  223. Monitor.Enter(this);
  224. }
  225. }
  226. }
  227. return false;
  228. }
  229. #region ISequence Members
  230. internal void AddRange<T>(ICollection<T> otherList) {
  231. foreach (object o in otherList) append(o);
  232. }
  233. [SpecialName]
  234. public virtual object InPlaceAdd(object other) {
  235. if (!Object.ReferenceEquals(this, other)) {
  236. IEnumerator e = PythonOps.GetEnumerator(other);
  237. while (e.MoveNext()) {
  238. append(e.Current);
  239. }
  240. } else {
  241. InPlaceMultiply(2);
  242. }
  243. return this;
  244. }
  245. [SpecialName]
  246. public List InPlaceMultiply(int count) {
  247. lock (this) {
  248. int n = this._size;
  249. int newCount = n * count;
  250. EnsureSize(newCount);
  251. int block = n;
  252. int pos = n;
  253. while (pos < newCount) {
  254. Array.Copy(_data, 0, _data, pos, Math.Min(block, newCount - pos));
  255. pos += block;
  256. block *= 2;
  257. }
  258. this._size = newCount;
  259. }
  260. return this;
  261. }
  262. [SpecialName]
  263. public object InPlaceMultiply(object count) {
  264. return PythonOps.MultiplySequence<List>(InPlaceMultiplyWorker, this, count, true);
  265. }
  266. private static List InPlaceMultiplyWorker(List self, int count) {
  267. return self.InPlaceMultiply(count);
  268. }
  269. public virtual object __getslice__(int start, int stop) {
  270. lock (this) {
  271. Slice.FixSliceArguments(_size, ref start, ref stop);
  272. object[] ret = ArrayOps.GetSlice(_data, start, stop);
  273. return new List(ret);
  274. }
  275. }
  276. internal object[] GetSliceAsArray(int start, int stop) {
  277. if (start < 0) start = 0;
  278. if (stop > __len__()) stop = __len__();
  279. lock (this) return ArrayOps.GetSlice(_data, start, stop);
  280. }
  281. public virtual void __setslice__(int start, int stop, object value) {
  282. Slice.FixSliceArguments(_size, ref start, ref stop);
  283. if (start > stop) return;
  284. SliceNoStep(start, stop, value);
  285. }
  286. public virtual void __delslice__(int start, int stop) {
  287. lock (this) {
  288. Slice.FixSliceArguments(_size, ref start, ref stop);
  289. if (start > stop) return;
  290. int i = start;
  291. for (int j = stop; j < _size; j++, i++) {
  292. _data[i] = _data[j];
  293. }
  294. _size -= stop - start;
  295. }
  296. }
  297. public virtual object this[Slice slice] {
  298. get {
  299. if (slice == null) throw PythonOps.TypeError("list indicies must be integer or slice, not None");
  300. int start, stop, step;
  301. slice.indices(_size, out start, out stop, out step);
  302. if ((step > 0 && start >= stop) || (step < 0 && start <= stop)) return new List();
  303. if (step == 1) {
  304. object[] ret;
  305. lock (this) ret = ArrayOps.GetSlice(_data, start, stop);
  306. return new List(ret);
  307. } else {
  308. // start/stop/step could be near Int32.MaxValue, and simply addition could cause overflow
  309. int n = (int)(step > 0 ? (0L + stop - start + step - 1) / step : (0L + stop - start + step + 1) / step);
  310. object[] ret = new object[n];
  311. lock (this) {
  312. int ri = 0;
  313. for (int i = 0, index = start; i < n; i++, index += step) {
  314. ret[ri++] = _data[index];
  315. }
  316. }
  317. return new List(ret);
  318. }
  319. }
  320. set {
  321. if (slice == null) throw PythonOps.TypeError("list indicies must be integer or slice, not None");
  322. if (slice.step != null) {
  323. // try to assign back to self: make a copy first
  324. if (this == value) value = new List(value);
  325. slice.DoSliceAssign(this.SliceAssign, _size, value);
  326. } else {
  327. int start, stop, step;
  328. slice.indices(_size, out start, out stop, out step);
  329. if (start > stop) return;
  330. SliceNoStep(start, stop, value);
  331. }
  332. }
  333. }
  334. private void SliceNoStep(int start, int stop, object value) {
  335. IEnumerator enumerator = PythonOps.GetEnumerator(value);
  336. // save a ref to myData incase other calls cause us
  337. // to re-size.
  338. List newList = new List(_data.Length); // race is tolerable...
  339. lock (this) {
  340. for (int i = 0; i < start; i++) {
  341. newList.AddNoLock(_data[i]);
  342. }
  343. }
  344. // calling user code, get rid of the lock...
  345. while (enumerator.MoveNext()) {
  346. newList.AddNoLock(enumerator.Current);
  347. }
  348. lock (this) {
  349. for (int i = stop; i < _size; i++) {
  350. newList.AddNoLock(_data[i]);
  351. }
  352. if (newList._data.Length < _data.Length) {
  353. // shrinking our array may result in IndexOutOfRange in
  354. // this[...] where we read w/o a lock.
  355. Array.Copy(newList._data, _data, newList._data.Length);
  356. } else {
  357. this._data = newList._data;
  358. }
  359. this._size = newList._size;
  360. }
  361. }
  362. private void SliceAssign(int index, object value) {
  363. this[index] = value;
  364. }
  365. public virtual void __delitem__(int index) {
  366. lock (this) RawDelete(PythonOps.FixIndex(index, _size));
  367. }
  368. public virtual void __delitem__(object index) {
  369. __delitem__(Converter.ConvertToIndex(index));
  370. }
  371. public void __delitem__(Slice slice) {
  372. if (slice == null) throw PythonOps.TypeError("list indicies must be integers or slices");
  373. lock (this) {
  374. int start, stop, step;
  375. // slice is sealed, indicies can't be user code...
  376. slice.indices(_size, out start, out stop, out step);
  377. if (step > 0 && (start >= stop)) return;
  378. if (step < 0 && (start <= stop)) return;
  379. if (step == 1) {
  380. int i = start;
  381. for (int j = stop; j < _size; j++, i++) {
  382. _data[i] = _data[j];
  383. }
  384. _size -= stop - start;
  385. return;
  386. }
  387. if (step == -1) {
  388. int i = stop + 1;
  389. for (int j = start + 1; j < _size; j++, i++) {
  390. _data[i] = _data[j];
  391. }
  392. _size -= start - stop;
  393. return;
  394. }
  395. if (step < 0) {
  396. // find "start" we will skip in the 1,2,3,... order
  397. int i = start;
  398. while (i > stop) {
  399. i += step;
  400. }
  401. i -= step;
  402. // swap start/stop, make step positive
  403. stop = start + 1;
  404. start = i;
  405. step = -step;
  406. }
  407. int curr, skip, move;
  408. // skip: the next position we should skip
  409. // curr: the next position we should fill in data
  410. // move: the next position we will check
  411. curr = skip = move = start;
  412. while (curr < stop && move < stop) {
  413. if (move != skip) {
  414. _data[curr++] = _data[move];
  415. } else
  416. skip += step;
  417. move++;
  418. }
  419. while (stop < _size) {
  420. _data[curr++] = _data[stop++];
  421. }
  422. _size = curr;
  423. }
  424. }
  425. #endregion
  426. private void RawDelete(int index) {
  427. int len = _size - 1;
  428. _size = len;
  429. object[] tempData = _data;
  430. for (int i = index; i < len; i++) {
  431. tempData[i] = tempData[i + 1];
  432. }
  433. tempData[len] = null;
  434. }
  435. internal void EnsureSize(int needed) {
  436. if (_data.Length >= needed) return;
  437. if (_data.Length == 0) {
  438. // free growth, we wasted nothing
  439. _data = new object[4];
  440. return;
  441. }
  442. int newSize = Math.Max(_size * 3, 10);
  443. while (newSize < needed) newSize *= 2;
  444. #if ALLOC_DEBUG
  445. growthCnt++;
  446. growthSize += _size;
  447. Console.Error.WriteLine("Growing {3} {0} {1} avg {2}", growthCnt, growthSize, growthSize/growthCnt, newSize - _size);
  448. #endif
  449. _data = ArrayOps.CopyArray(_data, newSize);
  450. }
  451. public void append(object item) {
  452. lock (this) {
  453. AddNoLock(item);
  454. }
  455. }
  456. /// <summary>
  457. /// Non-thread safe adder, should only be used by internal callers that
  458. /// haven't yet exposed their list.
  459. /// </summary>
  460. internal void AddNoLock(object item) {
  461. EnsureSize(_size + 1);
  462. _data[_size] = item;
  463. _size += 1;
  464. }
  465. internal void AddNoLockNoDups(object item) {
  466. for (int i = 0; i < _size; i++) {
  467. if (PythonOps.EqualRetBool(_data[i], item)) {
  468. return;
  469. }
  470. }
  471. AddNoLock(item);
  472. }
  473. internal void AppendListNoLockNoDups(List list) {
  474. if (list != null) {
  475. foreach (object item in list) {
  476. AddNoLockNoDups(item);
  477. }
  478. }
  479. }
  480. public int count(object item) {
  481. lock (this) {
  482. int cnt = 0;
  483. for (int i = 0, len = _size; i < len; i++) {
  484. object val = _data[i];
  485. Monitor.Exit(this);
  486. try {
  487. if (PythonOps.EqualRetBool(val, item)) cnt++;
  488. } finally {
  489. Monitor.Enter(this);
  490. }
  491. }
  492. return cnt;
  493. }
  494. }
  495. public void extend(object seq) {
  496. //!!! optimize case of easy sequence (List or Tuple)
  497. IEnumerator i = PythonOps.GetEnumerator(seq);
  498. if (seq == (object)this) {
  499. List other = new List(i);
  500. i = ((IEnumerable)other).GetEnumerator();
  501. }
  502. while (i.MoveNext()) append(i.Current);
  503. }
  504. public int index(object item) {
  505. return index(item, 0, _size);
  506. }
  507. public int index(object item, int start) {
  508. return index(item, start, _size);
  509. }
  510. public int index(object item, int start, int stop) {
  511. // CPython behavior for index is to only look at the
  512. // original items. If new items are added they
  513. // are ignored, but if items are removed they
  514. // aren't iterated. We therefore get a stable view
  515. // of our data, and then go with the minimum between
  516. // our starting size and ending size.
  517. object[] locData;
  518. int locSize;
  519. lock (this) {
  520. // get a stable view on size / data...
  521. locData = _data;
  522. locSize = _size;
  523. }
  524. start = PythonOps.FixSliceIndex(start, locSize);
  525. stop = PythonOps.FixSliceIndex(stop, locSize);
  526. for (int i = start; i < Math.Min(stop, Math.Min(locSize, _size)); i++) {
  527. if (PythonOps.EqualRetBool(locData[i], item)) return i;
  528. }
  529. throw PythonOps.ValueError("list.index(item): item not in list");
  530. }
  531. public int index(object item, object start) {
  532. return index(item, Converter.ConvertToIndex(start), _size);
  533. }
  534. public int index(object item, object start, object stop) {
  535. return index(item, Converter.ConvertToIndex(start), Converter.ConvertToIndex(stop));
  536. }
  537. public void insert(int index, object value) {
  538. if (index >= _size) {
  539. append(value);
  540. return;
  541. }
  542. lock (this) {
  543. index = PythonOps.FixSliceIndex(index, _size);
  544. EnsureSize(_size + 1);
  545. _size += 1;
  546. for (int i = _size - 1; i > index; i--) {
  547. _data[i] = _data[i - 1];
  548. }
  549. _data[index] = value;
  550. }
  551. }
  552. void IList.Insert(int index, object value) {
  553. insert(index, value);
  554. }
  555. public object pop() {
  556. if (this._size == 0) throw PythonOps.IndexError("pop off of empty list");
  557. lock (this) {
  558. this._size -= 1;
  559. return _data[this._size];
  560. }
  561. }
  562. public object pop(int index) {
  563. lock (this) {
  564. index = PythonOps.FixIndex(index, _size);
  565. if (_size == 0) throw PythonOps.IndexError("pop off of empty list");
  566. object ret = _data[index];
  567. _size -= 1;
  568. for (int i = index; i < _size; i++) {
  569. _data[i] = _data[i + 1];
  570. }
  571. return ret;
  572. }
  573. }
  574. public void remove(object value) {
  575. lock (this) RawDelete(index(value));
  576. }
  577. void IList.Remove(object value) {
  578. remove(value);
  579. }
  580. public void reverse() {
  581. lock (this) Array.Reverse(_data, 0, _size);
  582. }
  583. internal void reverse(int index, int count) {
  584. lock (this) Array.Reverse(_data, index, count);
  585. }
  586. private class DefaultPythonComparer : IComparer {
  587. public static readonly DefaultPythonComparer Instance = new DefaultPythonComparer();
  588. private DynamicSite<object, object, int> site = DynamicSite<object, object, int>.Create(DoOperationAction.Make(DefaultContext.DefaultPythonBinder, Operators.Compare));
  589. public DefaultPythonComparer() { }
  590. public int Compare(object x, object y) {
  591. //??? Putting this optimization here is awfully special case, but comes close to halving sort time for int lists
  592. // if (x is int && y is int) {
  593. // int xi = (int)x;
  594. // int yi = (int)y;
  595. // return xi == yi ? 0 : (xi < yi ? -1 : +1);
  596. // }
  597. return site.Invoke(DefaultContext.DefaultCLS, x, y);
  598. }
  599. }
  600. private class FunctionComparer : IComparer {
  601. //??? optimized version when we know we have a Function
  602. private object cmpfunc;
  603. private DynamicSite<object, object, object, int> FuncSite =
  604. CallSiteFactory.CreateSimpleCallSite<object, object, object, int>(DefaultContext.DefaultPythonBinder);
  605. public FunctionComparer(object cmpfunc) { this.cmpfunc = cmpfunc; }
  606. public int Compare(object o1, object o2) {
  607. return FuncSite.Invoke(DefaultContext.Default, cmpfunc, o1, o2);
  608. }
  609. }
  610. public void sort() {
  611. sort(null, null, false);
  612. }
  613. public void sort(object cmp) {
  614. sort(cmp, null, false);
  615. }
  616. public void sort(object cmp, object key) {
  617. sort(cmp, key, false);
  618. }
  619. public void sort([DefaultParameterValue(null)] object cmp,
  620. [DefaultParameterValue(null)] object key,
  621. [DefaultParameterValue(false)] bool reverse) {
  622. IComparer comparer = (cmp == null) ?
  623. (IComparer)new DefaultPythonComparer() :
  624. (IComparer)new FunctionComparer(cmp);
  625. DoSort(comparer, key, reverse, 0, _size);
  626. }
  627. internal void DoSort(IComparer cmp, object key, bool reverse, int index, int count) {
  628. lock (this) {
  629. object[] sortData = _data;
  630. int sortSize = _size;
  631. try {
  632. // make the list appear empty for the duration of the sort...
  633. _data = ArrayUtils.EmptyObjects;
  634. _size = 0;
  635. if (key != null) {
  636. object[] keys = new object[sortSize];
  637. for (int i = 0; i < sortSize; i++) {
  638. Debug.Assert(_data.Length == 0);
  639. keys[i] = PythonCalls.Call(key, sortData[i]);
  640. if (_data.Length != 0) throw PythonOps.ValueError("list mutated while determing keys");
  641. }
  642. sortData = ListMergeSort(sortData, keys, cmp, index, count, reverse);
  643. } else {
  644. sortData = ListMergeSort(sortData, cmp, index, count, reverse);
  645. }
  646. } finally {
  647. // restore the list to it's old data & size (which is now supported appropriately)
  648. _data = sortData;
  649. _size = sortSize;
  650. }
  651. }
  652. }
  653. internal object[] ListMergeSort(object[] sortData, IComparer cmp, int index, int count, bool reverse) {
  654. return ListMergeSort(sortData, null, cmp, index, count, reverse);
  655. }
  656. internal object[] ListMergeSort(object[] sortData, object[] keys, IComparer cmp, int index, int count, bool reverse) {
  657. if (count - index < 2) return sortData; // 1 or less items, we're sorted, quit now...
  658. if (keys == null) keys = sortData;
  659. // list merge sort - stable sort w/ a minimum # of comparisons.
  660. int len = count - index;
  661. // prepare the two lists.
  662. int[] lists = new int[len + 2]; //0 and count + 1 are auxillary fields
  663. lists[0] = 1;
  664. lists[len + 1] = 2;
  665. for (int i = 1; i <= len - 2; i++) {
  666. lists[i] = -(i + 2);
  667. }
  668. lists[len - 1] = lists[len] = 0;
  669. // new pass
  670. for (; ; ) {
  671. // p & q traverse the lists during each pass.
  672. // s is usually the most most recently processed record of the current sublist
  673. // t points to the end of the previously output sublist
  674. int s = 0;
  675. int t = len + 1;
  676. int p = lists[s];
  677. int q = lists[t];
  678. if (q == 0) break; // we're done
  679. for (; ; ) {
  680. // Indexes into the array here are 1 based. 0 is a
  681. // virtual element and so is (len - 1) - they only exist in
  682. // the length array.
  683. if ((p < 1) || (q <= len && DoCompare(keys, cmp, p + index - 1, q + index - 1, reverse))) {
  684. // advance p
  685. if (lists[s] < 0) lists[s] = Math.Abs(p) * -1;
  686. else lists[s] = Math.Abs(p);
  687. s = p;
  688. p = lists[p];
  689. if (p > 0) continue;
  690. // complete the sublist
  691. lists[s] = q;
  692. s = t;
  693. do {
  694. t = q;
  695. q = lists[q];
  696. } while (q > 0);
  697. } else {
  698. // advance q
  699. if (lists[s] < 0) lists[s] = Math.Abs(q) * -1;
  700. else lists[s] = Math.Abs(q);
  701. s = q;
  702. q = lists[q];
  703. if (q > 0) continue;
  704. // Complete the sublist
  705. lists[s] = p;
  706. s = t;
  707. do {
  708. t = p;
  709. p = lists[p];
  710. } while (p > 0);
  711. }
  712. Debug.Assert(p <= 0);
  713. Debug.Assert(q <= 0);
  714. p *= -1;
  715. q *= -1;
  716. if (q == 0) {
  717. if (lists[s] < 0) lists[s] = Math.Abs(p) * -1;
  718. else lists[s] = Math.Abs(p);
  719. lists[t] = 0;
  720. // go back to new pass
  721. break;
  722. } // else keep going
  723. }
  724. }
  725. // use the resulting indicies to
  726. // extract the order.
  727. object[] newData = new object[len];
  728. int start = lists[0];
  729. int outIndex = 0;
  730. while (start != 0) {
  731. newData[outIndex++] = sortData[start + index - 1];
  732. start = lists[start];
  733. }
  734. if (sortData.Length != count || index != 0) {
  735. for (int j = 0; j < count; j++) {
  736. sortData[j + index] = newData[j];
  737. }
  738. } else {
  739. sortData = newData;
  740. }
  741. return sortData;
  742. }
  743. /// <summary>
  744. /// Compares the two specified keys
  745. /// </summary>
  746. private bool DoCompare(object[] keys, IComparer cmp, int p, int q, bool reverse) {
  747. Debug.Assert(_data.Length == 0);
  748. int result = cmp.Compare(keys[p], keys[q]);
  749. bool ret = reverse ? (result >= 0) : (result <= 0);
  750. if (_data.Length != 0) throw PythonOps.ValueError("list mutated during sort");
  751. return ret;
  752. }
  753. internal int BinarySearch(int index, int count, object value, IComparer comparer) {
  754. lock (this) return Array.BinarySearch(_data, index, count, value, comparer);
  755. }
  756. internal int CompareToWorker(List l) {
  757. using (new OrderedLocker(this, l)) {
  758. return PythonOps.CompareArrays(_data, _size, l._data, l._size);
  759. }
  760. }
  761. #region IList Members
  762. bool IList.IsReadOnly {
  763. get { return false; }
  764. }
  765. public virtual object this[int index] {
  766. get {
  767. // no locks works here, we either return an
  768. // old item (as if we were called first) or return
  769. // a current item...
  770. // force reading the array first, _size can change after
  771. object[] data = GetData();
  772. return data[PythonOps.FixIndex(index, _size)];
  773. }
  774. set {
  775. // but we need a lock here incase we're assigning
  776. // while re-sizing.
  777. lock (this) _data[PythonOps.FixIndex(index, _size)] = value;
  778. }
  779. }
  780. public virtual object this[BigInteger index] {
  781. get {
  782. return this[index.ToInt32()];
  783. }
  784. set {
  785. this[index.ToInt32()] = value;
  786. }
  787. }
  788. /// <summary>
  789. /// Supports __index__ on arbitrary types, also prevents __float__
  790. /// </summary>
  791. public virtual object this[object index] {
  792. get {
  793. return this[Converter.ConvertToIndex(index)];
  794. }
  795. set {
  796. this[Converter.ConvertToIndex(index)] = value;
  797. }
  798. }
  799. [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
  800. private object[] GetData() {
  801. return _data;
  802. }
  803. void IList.RemoveAt(int index) {
  804. lock (this) RawDelete(index);
  805. }
  806. bool IList.Contains(object value) {
  807. return __contains__(value);
  808. }
  809. void IList.Clear() {
  810. lock (this) _size = 0;
  811. }
  812. int IList.IndexOf(object value) {
  813. // we get a stable view of the list, and if user code
  814. // clears it then we'll stop iterating.
  815. object[] locData;
  816. int locSize;
  817. lock (this) {
  818. locData = _data;
  819. locSize = _size;
  820. }
  821. for (int i = 0; i < Math.Min(locSize, _size); i++) {
  822. if (PythonOps.EqualRetBool(locData[i], value)) return i;
  823. }
  824. return -1;
  825. }
  826. int IList.Add(object value) {
  827. lock (this) {
  828. AddNoLock(value);
  829. return _size - 1;
  830. }
  831. }
  832. bool IList.IsFixedSize {
  833. get { return false; }
  834. }
  835. #endregion
  836. #region ICollection Members
  837. bool ICollection.IsSynchronized {
  838. get { return false; }
  839. }
  840. int ICollection.Count {
  841. get { return __len__(); }
  842. }
  843. void ICollection.CopyTo(Array array, int index) {
  844. Array.Copy(_data, 0, array, index, _size);
  845. }
  846. internal void CopyTo(Array array, int index, int arrayIndex, int count) {
  847. Array.Copy(_data, index, array, arrayIndex, count);
  848. }
  849. object ICollection.SyncRoot {
  850. get {
  851. return this;
  852. }
  853. }
  854. #endregion
  855. #region IEnumerable Members
  856. IEnumerator IEnumerable.GetEnumerator() {
  857. return __iter__();
  858. }
  859. #endregion
  860. #region ICodeFormattable Members
  861. public virtual string/*!*/ __repr__(CodeContext/*!*/ context) {
  862. List<object> infinite = PythonOps.GetAndCheckInfinite(this);
  863. if (infinite == null) {
  864. return "[...]";
  865. }
  866. int index = infinite.Count;
  867. infinite.Add(this);
  868. try {
  869. StringBuilder buf = new StringBuilder();
  870. buf.Append("[");
  871. for (int i = 0; i < _size; i++) {
  872. if (i > 0) buf.Append(", ");
  873. buf.Append(PythonOps.StringRepr(_data[i]));
  874. }
  875. buf.Append("]");
  876. return buf.ToString();
  877. } finally {
  878. System.Diagnostics.Debug.Assert(index == infinite.Count - 1);
  879. infinite.RemoveAt(index);
  880. }
  881. }
  882. #endregion
  883. #region IValueEquality Members
  884. int IValueEquality.GetValueHashCode() {
  885. throw PythonOps.TypeError("list object is unhashable");
  886. }
  887. bool IValueEquality.ValueEquals(object other) {
  888. List l = other as List;
  889. if (l == null || l.__len__() != this.__len__()) return false;
  890. return CompareTo(l) == 0;
  891. }
  892. #endregion
  893. #region IList<object> Members
  894. int IList<object>.IndexOf(object item) {
  895. return ((IList)this).IndexOf(item);
  896. }
  897. void IList<object>.Insert(int index, object item) {
  898. this.insert(index, item);
  899. }
  900. void IList<object>.RemoveAt(int index) {
  901. ((IList)this).RemoveAt(index);
  902. }
  903. object IList<object>.this[int index] {
  904. get {
  905. return this[index];
  906. }
  907. set {
  908. this[index] = value;
  909. }
  910. }
  911. #endregion
  912. #region ICollection<object> Members
  913. void ICollection<object>.Add(object item) {
  914. append(item);
  915. }
  916. void ICollection<object>.Clear() {
  917. ((IList)this).Clear();
  918. }
  919. bool ICollection<object>.Contains(object item) {
  920. return this.__contains__(item);
  921. }
  922. void ICollection<object>.CopyTo(object[] array, int arrayIndex) {
  923. for (int i = 0; i < __len__(); i++) {
  924. array[arrayIndex + i] = this[i];
  925. }
  926. }
  927. int ICollection<object>.Count {
  928. get { return __len__(); }
  929. }
  930. bool ICollection<object>.IsReadOnly {
  931. get { return ((IList)this).IsReadOnly; }
  932. }
  933. bool ICollection<object>.Remove(object item) {
  934. if (this.__contains__(item)) {
  935. this.remove(item);
  936. return true;
  937. }
  938. return false;
  939. }
  940. #endregion
  941. #region IEnumerable<object> Members
  942. IEnumerator<object> IEnumerable<object>.GetEnumerator() {
  943. return new IEnumeratorOfTWrapper<object>(((IEnumerable)this).GetEnumerator());
  944. }
  945. #endregion
  946. private int CompareTo(List other) {
  947. CompareUtil.Push(this, other);
  948. try {
  949. return CompareToWorker(other);
  950. } finally {
  951. CompareUtil.Pop(this, other);
  952. }
  953. }
  954. #region Rich Comparison Members
  955. [return: MaybeNotImplemented]
  956. public static object operator > (List self, object other) {
  957. List l = other as List;
  958. if (l == null) return NotImplementedType.Value;
  959. return self.CompareTo(l) > 0 ? RuntimeHelpers.True : RuntimeHelpers.False;
  960. }
  961. [return: MaybeNotImplemented]
  962. public static object operator <(List self, object other) {
  963. List l = other as List;
  964. if (l == null) return NotImplementedType.Value;
  965. return self.CompareTo(l) < 0 ? RuntimeHelpers.True : RuntimeHelpers.False;
  966. }
  967. [return: MaybeNotImplemented]
  968. public static object operator >=(List self, object other) {
  969. List l = other as List;
  970. if (l == null) return NotImplementedType.Value;
  971. return self.CompareTo(l) >= 0 ? RuntimeHelpers.True : RuntimeHelpers.False;
  972. }
  973. [return: MaybeNotImplemented]
  974. public static object operator <=(List self, object other) {
  975. List l = other as List;
  976. if (l == null) return NotImplementedType.Value;
  977. return self.CompareTo(l) <= 0 ? RuntimeHelpers.True : RuntimeHelpers.False;
  978. }
  979. #endregion
  980. }
  981. public class listiterator : IEnumerator, IEnumerable, IEnumerable<object>, IEnumerator<object> {
  982. private int _index = -1;
  983. private List _list;
  984. private bool _iterating = true;
  985. public listiterator(List l) { _list = l; }
  986. #region IEnumerator Members
  987. public void Reset() {
  988. _index = -1;
  989. }
  990. public object Current {
  991. get {
  992. return _list._data[_index];
  993. }
  994. }
  995. public bool MoveNext() {
  996. if (_iterating) {
  997. _index++;
  998. _iterating = _index <= _list._size - 1;
  999. }
  1000. return _iterating;
  1001. }
  1002. public object __iter__() {
  1003. return this;
  1004. }
  1005. #endregion
  1006. #region IEnumerable Members
  1007. IEnumerator IEnumerable.GetEnumerator() {
  1008. return this;
  1009. }
  1010. #endregion
  1011. #region IDisposable Members
  1012. public void Dispose() {
  1013. Dispose(true);
  1014. GC.SuppressFinalize(this);
  1015. }
  1016. protected virtual void Dispose(bool disposing) {
  1017. }
  1018. #endregion
  1019. #region IEnumerable<object> Members
  1020. IEnumerator<object> IEnumerable<object>.GetEnumerator() {
  1021. return this;
  1022. }
  1023. #endregion
  1024. }
  1025. /// <summary>
  1026. /// we need to lock both objects (or copy all of one's data w/ it's lock held, and
  1027. /// then compare, which is bad). Therefore we have a strong order for locking on
  1028. /// the two objects based upon the hash code or object identity in case of a collision
  1029. /// </summary>
  1030. public class OrderedLocker : IDisposable {
  1031. private readonly object _one, _two;
  1032. public OrderedLocker(object/*!*/ one, object/*!*/ two) {
  1033. Debug.Assert(one != null); Debug.Assert(two != null);
  1034. _one = one;
  1035. _two = two;
  1036. int hc1 = System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(_one);
  1037. int hc2 = System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(_two);
  1038. if (hc1 < hc2) {
  1039. Monitor.Enter(_one);
  1040. Monitor.Enter(_two);
  1041. } else if (hc1 != hc2) {
  1042. Monitor.Enter(_two);
  1043. Monitor.Enter(_one);
  1044. } else {
  1045. // rare, but possible. We need a second opinion
  1046. if (IdDispenser.GetId(_one) < IdDispenser.GetId(_two)) {
  1047. Monitor.Enter(_one);
  1048. Monitor.Enter(_two);
  1049. } else {
  1050. Monitor.Enter(_two);
  1051. Monitor.Enter(_one);
  1052. }
  1053. }
  1054. }
  1055. #region IDisposable Members
  1056. public void Dispose() {
  1057. Monitor.Exit(_one);
  1058. Monitor.Exit(_two);
  1059. }
  1060. #endregion
  1061. }
  1062. }