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

/IronPython_1_0/Src/IronPython/Runtime/List.cs

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