PageRenderTime 53ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/IronPython_1_1/Src/IronPython/Runtime/List.cs

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