PageRenderTime 60ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/Merlin/Main/Languages/IronPython/IronPython/Runtime/List.cs

https://github.com/shri/ironruby
C# | 1577 lines | 1166 code | 290 blank | 121 comment | 211 complexity | 80e1fc6364706bfdd8cfe06df709045a MD5 | raw file
Possible License(s): LGPL-2.1, MIT, GPL-2.0, CC-BY-SA-3.0

Large files files are truncated, but you can click here to view the full 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.Diagnostics;
  19. using System.Runtime.InteropServices;
  20. using System.Text;
  21. using System.Threading;
  22. using IronPython.Runtime.Operations;
  23. using IronPython.Runtime.Types;
  24. using Microsoft.Scripting;
  25. using Microsoft.Scripting.Generation;
  26. using Microsoft.Scripting.Math;
  27. using Microsoft.Scripting.Runtime;
  28. using Microsoft.Scripting.Utils;
  29. using SpecialNameAttribute = System.Runtime.CompilerServices.SpecialNameAttribute;
  30. namespace IronPython.Runtime {
  31. [PythonType("list"), Serializable, System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
  32. public class List : IList, ICodeFormattable, IValueEquality, IList<object>, IReversible {
  33. internal int _size;
  34. internal volatile object[] _data;
  35. public void __init__() {
  36. _data = new object[8];
  37. _size = 0;
  38. }
  39. public void __init__([NotNull] IEnumerable enumerable) {
  40. __init__();
  41. foreach (object o in enumerable) {
  42. AddNoLock(o);
  43. }
  44. }
  45. public void __init__([NotNull] ICollection sequence) {
  46. _data = new object[sequence.Count];
  47. int i = 0;
  48. foreach (object item in sequence) {
  49. _data[i++] = item;
  50. }
  51. _size = i;
  52. }
  53. public void __init__([NotNull] List sequence) {
  54. if (this == sequence) {
  55. // list.__init__(l, l) resets l
  56. _size = 0;
  57. return;
  58. }
  59. _data = new object[sequence._size];
  60. object[] data = sequence._data;
  61. for (int i = 0; i < _data.Length; i++) {
  62. _data[i] = data[i];
  63. }
  64. _size = _data.Length;
  65. }
  66. public void __init__([NotNull] string sequence) {
  67. _data = new object[sequence.Length];
  68. _size = sequence.Length;
  69. for (int i = 0; i < sequence.Length; i++) {
  70. _data[i] = ScriptingRuntimeHelpers.CharToString(sequence[i]);
  71. }
  72. }
  73. public void __init__(CodeContext context, object sequence) {
  74. try {
  75. object len;
  76. if (PythonTypeOps.TryInvokeUnaryOperator(context, sequence, "__len__", out len)) {
  77. int ilen = PythonContext.GetContext(context).ConvertToInt32(len);
  78. _data = new object[ilen];
  79. _size = 0;
  80. extend(sequence);
  81. } else {
  82. _data = new object[20];
  83. _size = 0;
  84. extend(sequence);
  85. }
  86. } catch (MissingMemberException) {
  87. _data = new object[20];
  88. _size = 0;
  89. extend(sequence);
  90. }
  91. }
  92. public static object __new__(CodeContext/*!*/ context, PythonType cls) {
  93. if (cls == TypeCache.List) {
  94. return new List();
  95. }
  96. return cls.CreateInstance(context);
  97. }
  98. public static object __new__(CodeContext/*!*/ context, PythonType cls, object arg) {
  99. return __new__(context, cls);
  100. }
  101. public static object __new__(CodeContext/*!*/ context, PythonType cls, params object[] args\u00F8) {
  102. return __new__(context, cls);
  103. }
  104. public static object __new__(CodeContext/*!*/ context, PythonType cls, [ParamDictionary]IDictionary<object, object> kwArgs\u00F8, params object[] args\u00F8) {
  105. return __new__(context, cls);
  106. }
  107. private List(IEnumerator e)
  108. : this(10) {
  109. while (e.MoveNext()) AddNoLock(e.Current);
  110. }
  111. internal List(int capacity) {
  112. if (capacity == 0) {
  113. _data = ArrayUtils.EmptyObjects;
  114. } else {
  115. _data = new object[capacity];
  116. }
  117. }
  118. private List(params object[] items) {
  119. _data = items;
  120. _size = _data.Length;
  121. }
  122. public List()
  123. : this(0) {
  124. }
  125. #if ALLOC_DEBUG
  126. private static int total, totalSize, cnt, growthCnt, growthSize;
  127. ~List() {
  128. total += _data.Length;
  129. totalSize += _size;
  130. cnt++;
  131. Console.Error.WriteLine("List: allocated {0} used {1} total wasted {2} - grand total wasted {3}", _data.Length, _size, total-totalSize, growthSize + total - totalSize);
  132. Console.Error.WriteLine(" Growing {0} {1} avg {2}", growthCnt, growthSize, growthSize / growthCnt);
  133. }
  134. #endif
  135. internal List(object sequence) {
  136. ICollection items = sequence as ICollection;
  137. object len;
  138. if (items != null) {
  139. _data = new object[items.Count];
  140. int i = 0;
  141. foreach (object item in items) {
  142. _data[i++] = item;
  143. }
  144. _size = i;
  145. } else if (PythonTypeOps.TryInvokeUnaryOperator(DefaultContext.Default,
  146. sequence,
  147. "__len__",
  148. out len)) {
  149. int ilen = Converter.ConvertToInt32(len);
  150. _data = new object[ilen];
  151. extend(sequence);
  152. } else {
  153. _data = new object[20];
  154. extend(sequence);
  155. }
  156. }
  157. internal List(ICollection items)
  158. : this(items.Count) {
  159. int i = 0;
  160. foreach (object item in items) {
  161. _data[i++] = item;
  162. }
  163. _size = i;
  164. }
  165. /// <summary>
  166. /// Creates a new list with the data in the array and a size
  167. /// the same as the length of the array. The array is held
  168. /// onto and may be mutated in the future by the list.
  169. /// </summary>
  170. /// <param name="data">params array to use for lists storage</param>
  171. internal static List FromArrayNoCopy(params object[] data) {
  172. return new List(data);
  173. }
  174. internal object[] GetObjectArray() {
  175. lock (this) {
  176. return ArrayOps.CopyArray(_data, _size);
  177. }
  178. }
  179. #region binary operators
  180. public static List operator +([NotNull]List l1, [NotNull]List l2) {
  181. object[] ret;
  182. int size;
  183. lock (l1) {
  184. ret = ArrayOps.CopyArray(l1._data, GetAddSize(l1._size, l2._size));
  185. size = l1._size;
  186. }
  187. lock (l2) {
  188. if (l2._size + size > ret.Length) {
  189. ret = ArrayOps.CopyArray(ret, GetAddSize(size, l2._size));
  190. }
  191. Array.Copy(l2._data, 0, ret, size, l2._size);
  192. List lret = new List(ret);
  193. lret._size = size + l2._size;
  194. return lret;
  195. }
  196. }
  197. /// <summary>
  198. /// Gets a reasonable size for the addition of two arrays. We round
  199. /// to a power of two so that we usually have some extra space if
  200. /// the resulting array gets added to.
  201. /// </summary>
  202. private static int GetAddSize(int s1, int s2) {
  203. int length = s1 + s2;
  204. return GetNewSize(length);
  205. }
  206. private static int GetNewSize(int length) {
  207. if (length > 256) {
  208. return length + (128 - 1) & ~(128 - 1);
  209. }
  210. return length + (16 - 1) & ~(16 - 1);
  211. }
  212. public static List operator *([NotNull]List l, int count) {
  213. return MultiplyWorker(l, count);
  214. }
  215. public static List operator *(int count, List l) {
  216. return MultiplyWorker(l, count);
  217. }
  218. public static object operator *([NotNull]List self, [NotNull]Index count) {
  219. return PythonOps.MultiplySequence<List>(MultiplyWorker, self, count, true);
  220. }
  221. public static object operator *([NotNull]Index count, [NotNull]List self) {
  222. return PythonOps.MultiplySequence<List>(MultiplyWorker, self, count, false);
  223. }
  224. public static object operator *([NotNull]List self, object count) {
  225. int index;
  226. if (Converter.TryConvertToIndex(count, out index)) {
  227. return self * index;
  228. }
  229. throw PythonOps.TypeErrorForUnIndexableObject(count);
  230. }
  231. public static object operator *(object count, [NotNull]List self) {
  232. int index;
  233. if (Converter.TryConvertToIndex(count, out index)) {
  234. return index * self;
  235. }
  236. throw PythonOps.TypeErrorForUnIndexableObject(count);
  237. }
  238. private static List MultiplyWorker(List self, int count) {
  239. if (count <= 0) return PythonOps.MakeEmptyList(0);
  240. int n, newCount;
  241. object[] ret;
  242. lock (self) {
  243. n = self._size;
  244. //??? is this useful optimization
  245. //???if (n == 1) return new List(Array.ArrayList.Repeat(this[0], count));
  246. newCount = checked(n * count);
  247. ret = ArrayOps.CopyArray(self._data, newCount);
  248. }
  249. // this should be extremely fast for large count as it uses the same algoithim as efficient integer powers
  250. // ??? need to test to see how large count and n need to be for this to be fastest approach
  251. int block = n;
  252. int pos = n;
  253. while (pos < newCount) {
  254. Array.Copy(ret, 0, ret, pos, Math.Min(block, newCount - pos));
  255. pos += block;
  256. block *= 2;
  257. }
  258. return new List(ret);
  259. }
  260. #endregion
  261. public virtual int __len__() {
  262. return _size;
  263. }
  264. public virtual IEnumerator __iter__() {
  265. // return type is strongly typed to IEnumerator so that
  266. // we can call it w/o requiring an explicit conversion. If the
  267. // user overrides this we'll place a conversion in the wrapper
  268. // helper
  269. return new ListIterator(this);
  270. }
  271. public virtual IEnumerator __reversed__() {
  272. return new ListReverseIterator(this);
  273. }
  274. public virtual bool __contains__(object value) {
  275. return ContainsWorker(value);
  276. }
  277. internal bool ContainsWorker(object value) {
  278. bool lockTaken = false;
  279. try {
  280. MonitorUtils.Enter(this, ref lockTaken);
  281. for (int i = 0; i < _size; i++) {
  282. object thisIndex = _data[i];
  283. // release the lock while we may call user code...
  284. MonitorUtils.Exit(this, ref lockTaken);
  285. try {
  286. if (PythonOps.EqualRetBool(thisIndex, value))
  287. return true;
  288. } finally {
  289. MonitorUtils.Enter(this, ref lockTaken);
  290. }
  291. }
  292. } finally {
  293. if (lockTaken) {
  294. Monitor.Exit(this);
  295. }
  296. }
  297. return false;
  298. }
  299. public const object __hash__ = null;
  300. #region ISequence Members
  301. internal void AddRange<T>(ICollection<T> otherList) {
  302. foreach (object o in otherList) append(o);
  303. }
  304. [SpecialName]
  305. public virtual object InPlaceAdd(object other) {
  306. if (!Object.ReferenceEquals(this, other)) {
  307. IEnumerator e = PythonOps.GetEnumerator(other);
  308. while (e.MoveNext()) {
  309. append(e.Current);
  310. }
  311. } else {
  312. InPlaceMultiply(2);
  313. }
  314. return this;
  315. }
  316. [SpecialName]
  317. public List InPlaceMultiply(int count) {
  318. lock (this) {
  319. int n = this._size;
  320. int newCount = checked(n * count);
  321. EnsureSize(newCount);
  322. int block = n;
  323. int pos = n;
  324. while (pos < newCount) {
  325. Array.Copy(_data, 0, _data, pos, Math.Min(block, newCount - pos));
  326. pos += block;
  327. block *= 2;
  328. }
  329. this._size = newCount;
  330. }
  331. return this;
  332. }
  333. [SpecialName]
  334. public object InPlaceMultiply(Index count) {
  335. return PythonOps.MultiplySequence<List>(InPlaceMultiplyWorker, this, count, true);
  336. }
  337. [SpecialName]
  338. public object InPlaceMultiply(object count) {
  339. int index;
  340. if (Converter.TryConvertToIndex(count, out index)) {
  341. return InPlaceMultiply(index);
  342. }
  343. throw PythonOps.TypeErrorForUnIndexableObject(count);
  344. }
  345. private static List InPlaceMultiplyWorker(List self, int count) {
  346. return self.InPlaceMultiply(count);
  347. }
  348. public virtual object __getslice__(int start, int stop) {
  349. lock (this) {
  350. Slice.FixSliceArguments(_size, ref start, ref stop);
  351. object[] ret = ArrayOps.GetSlice(_data, start, stop);
  352. return new List(ret);
  353. }
  354. }
  355. internal object[] GetSliceAsArray(int start, int stop) {
  356. if (start < 0) start = 0;
  357. if (stop > __len__()) stop = __len__();
  358. lock (this) return ArrayOps.GetSlice(_data, start, stop);
  359. }
  360. public virtual void __setslice__(int start, int stop, object value) {
  361. Slice.FixSliceArguments(_size, ref start, ref stop);
  362. if (value is List) {
  363. SliceNoStep(start, stop, (List)value);
  364. } else {
  365. SliceNoStep(start, stop, value);
  366. }
  367. }
  368. public virtual void __delslice__(int start, int stop) {
  369. lock (this) {
  370. Slice.FixSliceArguments(_size, ref start, ref stop);
  371. if (start > stop) return;
  372. int i = start;
  373. for (int j = stop; j < _size; j++, i++) {
  374. _data[i] = _data[j];
  375. }
  376. _size -= stop - start;
  377. }
  378. }
  379. private static readonly object _boxedOne = ScriptingRuntimeHelpers.Int32ToObject(1);
  380. public virtual object this[Slice slice] {
  381. get {
  382. if (slice == null) throw PythonOps.TypeError("list indices must be integer or slice, not None");
  383. int start, stop, step;
  384. slice.indices(_size, out start, out stop, out step);
  385. if ((step > 0 && start >= stop) || (step < 0 && start <= stop)) return new List();
  386. if (step == 1) {
  387. object[] ret;
  388. lock (this) ret = ArrayOps.GetSlice(_data, start, stop);
  389. return new List(ret);
  390. } else {
  391. // start/stop/step could be near Int32.MaxValue, and simply addition could cause overflow
  392. int n = (int)(step > 0 ? (0L + stop - start + step - 1) / step : (0L + stop - start + step + 1) / step);
  393. object[] ret = new object[n];
  394. lock (this) {
  395. int ri = 0;
  396. for (int i = 0, index = start; i < n; i++, index += step) {
  397. ret[ri++] = _data[index];
  398. }
  399. }
  400. return new List(ret);
  401. }
  402. }
  403. set {
  404. if (slice == null) throw PythonOps.TypeError("list indices must be integer or slice, not None");
  405. if (slice.step != null && (!(slice.step is int) || !slice.step.Equals(_boxedOne))) {
  406. // try to assign back to self: make a copy first
  407. if (this == value) value = new List(value);
  408. if (ValueRequiresNoLocks(value)) {
  409. // we don't need to worry about lock ordering of accesses to the
  410. // RHS & ourselves. We can lock once and avoid repeatedly locking/unlocking
  411. // on each assign.
  412. lock (this) {
  413. slice.DoSliceAssign(this.SliceAssignNoLock, _size, value);
  414. }
  415. } else {
  416. slice.DoSliceAssign(this.SliceAssign, _size, value);
  417. }
  418. } else {
  419. int start, stop, step;
  420. slice.indices(_size, out start, out stop, out step);
  421. List lstVal = value as List;
  422. if (lstVal != null) {
  423. SliceNoStep(start, stop, lstVal);
  424. } else {
  425. SliceNoStep(start, stop, value);
  426. }
  427. }
  428. }
  429. }
  430. private static bool ValueRequiresNoLocks(object value) {
  431. return value is PythonTuple || value is Array || value is FrozenSetCollection;
  432. }
  433. private void SliceNoStep(int start, int stop, List other) {
  434. // We don't lock other here - instead we read it's object array
  435. // and size therefore having a stable view even if it resizes.
  436. // This means if we had a multithreaded app like:
  437. //
  438. // T1 T2 T3
  439. // l1[:] = [1] * 100 l1[:] = [2] * 100 l3[:] = l1[:]
  440. //
  441. // we can end up with both 1s and 2s in the array. This is the
  442. // same as if our set was implemented on top of get/set item where
  443. // we'd take and release the locks repeatedly.
  444. int otherSize = other._size;
  445. object[] otherData = other._data;
  446. lock (this) {
  447. if ((stop - start) == otherSize) {
  448. // we are simply replacing values, this is fast...
  449. for (int i = 0; i < otherSize; i++) {
  450. _data[i + start] = otherData[i];
  451. }
  452. } else {
  453. // we are resizing the array (either bigger or smaller), we
  454. // will copy the data array and replace it all at once.
  455. stop = Math.Max(stop, start);
  456. int newSize = _size - (stop - start) + otherSize;
  457. object[] newData = new object[GetNewSize(newSize)];
  458. for (int i = 0; i < start; i++) {
  459. newData[i] = _data[i];
  460. }
  461. for (int i = 0; i < otherSize; i++) {
  462. newData[i + start] = otherData[i];
  463. }
  464. int writeOffset = otherSize - (stop - start);
  465. for (int i = stop; i < _size; i++) {
  466. newData[i + writeOffset] = _data[i];
  467. }
  468. _size = newSize;
  469. _data = newData;
  470. }
  471. }
  472. }
  473. private void SliceNoStep(int start, int stop, object value) {
  474. // always copy from a List object, even if it's a copy of some user defined enumerator. This
  475. // makes it easy to hold the lock for the duration fo the copy.
  476. IList<object> other = value as IList<object> ?? new List(PythonOps.GetEnumerator(value));
  477. lock (this) {
  478. if ((stop - start) == other.Count) {
  479. // we are simply replacing values, this is fast...
  480. for (int i = 0; i < other.Count; i++) {
  481. _data[i + start] = other[i];
  482. }
  483. } else {
  484. // we are resizing the array (either bigger or smaller), we
  485. // will copy the data array and replace it all at once.
  486. stop = Math.Max(stop, start);
  487. int newSize = _size - (stop - start) + other.Count;
  488. object[] newData = new object[GetNewSize(newSize)];
  489. for (int i = 0; i < start; i++) {
  490. newData[i] = _data[i];
  491. }
  492. for (int i = 0; i < other.Count; i++) {
  493. newData[i + start] = other[i];
  494. }
  495. int writeOffset = other.Count - (stop - start);
  496. for (int i = stop; i < _size; i++) {
  497. newData[i + writeOffset] = _data[i];
  498. }
  499. _size = newSize;
  500. _data = newData;
  501. }
  502. }
  503. }
  504. private void SliceAssign(int index, object value) {
  505. this[index] = value;
  506. }
  507. private void SliceAssignNoLock(int index, object value) {
  508. _data[index] = value;
  509. }
  510. public virtual void __delitem__(int index) {
  511. lock (this) RawDelete(PythonOps.FixIndex(index, _size));
  512. }
  513. public virtual void __delitem__(object index) {
  514. __delitem__(Converter.ConvertToIndex(index));
  515. }
  516. public void __delitem__(Slice slice) {
  517. if (slice == null) throw PythonOps.TypeError("list indices must be integers or slices");
  518. lock (this) {
  519. int start, stop, step;
  520. // slice is sealed, indices can't be user code...
  521. slice.indices(_size, out start, out stop, out step);
  522. if (step > 0 && (start >= stop)) return;
  523. if (step < 0 && (start <= stop)) return;
  524. if (step == 1) {
  525. int i = start;
  526. for (int j = stop; j < _size; j++, i++) {
  527. _data[i] = _data[j];
  528. }
  529. _size -= stop - start;
  530. return;
  531. }
  532. if (step == -1) {
  533. int i = stop + 1;
  534. for (int j = start + 1; j < _size; j++, i++) {
  535. _data[i] = _data[j];
  536. }
  537. _size -= start - stop;
  538. return;
  539. }
  540. if (step < 0) {
  541. // find "start" we will skip in the 1,2,3,... order
  542. int i = start;
  543. while (i > stop) {
  544. i += step;
  545. }
  546. i -= step;
  547. // swap start/stop, make step positive
  548. stop = start + 1;
  549. start = i;
  550. step = -step;
  551. }
  552. int curr, skip, move;
  553. // skip: the next position we should skip
  554. // curr: the next position we should fill in data
  555. // move: the next position we will check
  556. curr = skip = move = start;
  557. while (curr < stop && move < stop) {
  558. if (move != skip) {
  559. _data[curr++] = _data[move];
  560. } else
  561. skip += step;
  562. move++;
  563. }
  564. while (stop < _size) {
  565. _data[curr++] = _data[stop++];
  566. }
  567. _size = curr;
  568. }
  569. }
  570. #endregion
  571. private void RawDelete(int index) {
  572. int len = _size - 1;
  573. _size = len;
  574. object[] tempData = _data;
  575. for (int i = index; i < len; i++) {
  576. tempData[i] = tempData[i + 1];
  577. }
  578. tempData[len] = null;
  579. }
  580. internal void EnsureSize(int needed) {
  581. if (_data.Length >= needed) return;
  582. if (_data.Length == 0) {
  583. // free growth, we wasted nothing
  584. _data = new object[4];
  585. return;
  586. }
  587. int newSize = Math.Max(_size * 3, 10);
  588. while (newSize < needed) newSize *= 2;
  589. #if ALLOC_DEBUG
  590. growthCnt++;
  591. growthSize += _size;
  592. Console.Error.WriteLine("Growing {3} {0} {1} avg {2}", growthCnt, growthSize, growthSize/growthCnt, newSize - _size);
  593. #endif
  594. _data = ArrayOps.CopyArray(_data, newSize);
  595. }
  596. public void append(object item) {
  597. lock (this) {
  598. AddNoLock(item);
  599. }
  600. }
  601. /// <summary>
  602. /// Non-thread safe adder, should only be used by internal callers that
  603. /// haven't yet exposed their list.
  604. /// </summary>
  605. internal void AddNoLock(object item) {
  606. EnsureSize(_size + 1);
  607. _data[_size] = item;
  608. _size += 1;
  609. }
  610. internal void AddNoLockNoDups(object item) {
  611. for (int i = 0; i < _size; i++) {
  612. if (PythonOps.EqualRetBool(_data[i], item)) {
  613. return;
  614. }
  615. }
  616. AddNoLock(item);
  617. }
  618. internal void AppendListNoLockNoDups(List list) {
  619. if (list != null) {
  620. foreach (object item in list) {
  621. AddNoLockNoDups(item);
  622. }
  623. }
  624. }
  625. public int count(object item) {
  626. bool lockTaken = false;
  627. try {
  628. MonitorUtils.Enter(this, ref lockTaken);
  629. int cnt = 0;
  630. for (int i = 0, len = _size; i < len; i++) {
  631. object val = _data[i];
  632. MonitorUtils.Exit(this, ref lockTaken);
  633. try {
  634. if (PythonOps.EqualRetBool(val, item)) cnt++;
  635. } finally {
  636. MonitorUtils.Enter(this, ref lockTaken);
  637. }
  638. }
  639. return cnt;
  640. } finally {
  641. if (lockTaken) {
  642. Monitor.Exit(this);
  643. }
  644. }
  645. }
  646. public void extend([NotNull]List/*!*/ seq) {
  647. using(new OrderedLocker(this, seq)) {
  648. // use the original count for if we're extending this w/ this
  649. int count = seq.Count;
  650. EnsureSize(Count + count);
  651. for (int i = 0; i < count; i++) {
  652. AddNoLock(seq[i]);
  653. }
  654. }
  655. }
  656. public void extend([NotNull]PythonTuple/*!*/ seq) {
  657. lock (this) {
  658. EnsureSize(Count + seq.Count);
  659. for (int i = 0; i < seq.Count; i++) {
  660. AddNoLock(seq[i]);
  661. }
  662. }
  663. }
  664. public void extend(object seq) {
  665. IEnumerator i = PythonOps.GetEnumerator(seq);
  666. if (seq == (object)this) {
  667. List other = new List(i);
  668. i = ((IEnumerable)other).GetEnumerator();
  669. }
  670. while (i.MoveNext()) append(i.Current);
  671. }
  672. public int index(object item) {
  673. return index(item, 0, _size);
  674. }
  675. public int index(object item, int start) {
  676. return index(item, start, _size);
  677. }
  678. public int index(object item, int start, int stop) {
  679. // CPython behavior for index is to only look at the
  680. // original items. If new items are added they
  681. // are ignored, but if items are removed they
  682. // aren't iterated. We therefore get a stable view
  683. // of our data, and then go with the minimum between
  684. // our starting size and ending size.
  685. object[] locData;
  686. int locSize;
  687. lock (this) {
  688. // get a stable view on size / data...
  689. locData = _data;
  690. locSize = _size;
  691. }
  692. start = PythonOps.FixSliceIndex(start, locSize);
  693. stop = PythonOps.FixSliceIndex(stop, locSize);
  694. for (int i = start; i < Math.Min(stop, Math.Min(locSize, _size)); i++) {
  695. if (PythonOps.EqualRetBool(locData[i], item)) return i;
  696. }
  697. throw PythonOps.ValueError("list.index(item): item not in list");
  698. }
  699. public int index(object item, object start) {
  700. return index(item, Converter.ConvertToIndex(start), _size);
  701. }
  702. public int index(object item, object start, object stop) {
  703. return index(item, Converter.ConvertToIndex(start), Converter.ConvertToIndex(stop));
  704. }
  705. public void insert(int index, object value) {
  706. if (index >= _size) {
  707. append(value);
  708. return;
  709. }
  710. lock (this) {
  711. index = PythonOps.FixSliceIndex(index, _size);
  712. EnsureSize(_size + 1);
  713. _size += 1;
  714. for (int i = _size - 1; i > index; i--) {
  715. _data[i] = _data[i - 1];
  716. }
  717. _data[index] = value;
  718. }
  719. }
  720. [PythonHidden]
  721. public void Insert(int index, object value) {
  722. insert(index, value);
  723. }
  724. public object pop() {
  725. if (this._size == 0) throw PythonOps.IndexError("pop off of empty list");
  726. lock (this) {
  727. this._size -= 1;
  728. return _data[this._size];
  729. }
  730. }
  731. public object pop(int index) {
  732. lock (this) {
  733. index = PythonOps.FixIndex(index, _size);
  734. if (_size == 0) throw PythonOps.IndexError("pop off of empty list");
  735. object ret = _data[index];
  736. _size -= 1;
  737. for (int i = index; i < _size; i++) {
  738. _data[i] = _data[i + 1];
  739. }
  740. return ret;
  741. }
  742. }
  743. public void remove(object value) {
  744. lock (this) RawDelete(index(value));
  745. }
  746. void IList.Remove(object value) {
  747. remove(value);
  748. }
  749. public void reverse() {
  750. lock (this) Array.Reverse(_data, 0, _size);
  751. }
  752. internal void reverse(int index, int count) {
  753. lock (this) Array.Reverse(_data, index, count);
  754. }
  755. public void sort(CodeContext/*!*/ context) {
  756. sort(context, null, null, false);
  757. }
  758. public void sort(CodeContext/*!*/ context, object cmp) {
  759. sort(context, cmp, null, false);
  760. }
  761. public void sort(CodeContext/*!*/ context, object cmp, object key) {
  762. sort(context, cmp, key, false);
  763. }
  764. public void sort(CodeContext/*!*/ context,
  765. [DefaultParameterValue(null)] object cmp,
  766. [DefaultParameterValue(null)] object key,
  767. [DefaultParameterValue(false)] bool reverse) {
  768. // the empty list is already sorted
  769. if (_size != 0) {
  770. IComparer comparer = PythonContext.GetContext(context).GetComparer(
  771. cmp,
  772. GetComparisonType());
  773. DoSort(context, comparer, key, reverse, 0, _size);
  774. }
  775. }
  776. private Type GetComparisonType() {
  777. if (_size >= 4000) {
  778. // we're big, we can afford a custom comparison call site.
  779. return null;
  780. }
  781. if (_data.Length > 0) {
  782. // use the 1st index to determine the type - we're assuming lists are
  783. // homogeneous
  784. return CompilerHelpers.GetType(_data[0]);
  785. }
  786. return typeof(object);
  787. }
  788. internal void DoSort(CodeContext/*!*/ context, IComparer cmp, object key, bool reverse, int index, int count) {
  789. lock (this) {
  790. object[] sortData = _data;
  791. int sortSize = _size;
  792. try {
  793. // make the list appear empty for the duration of the sort...
  794. _data = ArrayUtils.EmptyObjects;
  795. _size = 0;
  796. if (key != null) {
  797. object[] keys = new object[sortSize];
  798. for (int i = 0; i < sortSize; i++) {
  799. Debug.Assert(_data.Length == 0);
  800. keys[i] = PythonCalls.Call(context, key, sortData[i]);
  801. if (_data.Length != 0) throw PythonOps.ValueError("list mutated while determing keys");
  802. }
  803. sortData = ListMergeSort(sortData, keys, cmp, index, count, reverse);
  804. } else {
  805. sortData = ListMergeSort(sortData, cmp, index, count, reverse);
  806. }
  807. } finally {
  808. // restore the list to it's old data & size (which is now supported appropriately)
  809. _data = sortData;
  810. _size = sortSize;
  811. }
  812. }
  813. }
  814. internal object[] ListMergeSort(object[] sortData, IComparer cmp, int index, int count, bool reverse) {
  815. return ListMergeSort(sortData, null, cmp, index, count, reverse);
  816. }
  817. internal object[] ListMergeSort(object[] sortData, object[] keys, IComparer cmp, int index, int count, bool reverse) {
  818. if (count - index < 2) return sortData; // 1 or less items, we're sorted, quit now...
  819. if (keys == null) keys = sortData;
  820. // list merge sort - stable sort w/ a minimum # of comparisons.
  821. int len = count - index;
  822. // prepare the two lists.
  823. int[] lists = new int[len + 2]; //0 and count + 1 are auxillary fields
  824. lists[0] = 1;
  825. lists[len + 1] = 2;
  826. for (int i = 1; i <= len - 2; i++) {
  827. lists[i] = -(i + 2);
  828. }
  829. lists[len - 1] = lists[len] = 0;
  830. // new pass
  831. for (; ; ) {
  832. // p & q traverse the lists during each pass.
  833. // s is usually the most most recently processed record of the current sublist
  834. // t points to the end of the previously output sublist
  835. int s = 0;
  836. int t = len + 1;
  837. int p = lists[s];
  838. int q = lists[t];
  839. if (q == 0) break; // we're done
  840. for (; ; ) {
  841. // Indexes into the array here are 1 based. 0 is a
  842. // virtual element and so is (len - 1) - they only exist in
  843. // the length array.
  844. if ((p < 1) || (q <= len && DoCompare(keys, cmp, p + index - 1, q + index - 1, reverse))) {
  845. // advance p
  846. if (lists[s] < 0) lists[s] = Math.Abs(p) * -1;
  847. else lists[s] = Math.Abs(p);
  848. s = p;
  849. p = lists[p];
  850. if (p > 0) continue;
  851. // complete the sublist
  852. lists[s] = q;
  853. s = t;
  854. do {
  855. t = q;
  856. q = lists[q];
  857. } while (q > 0);
  858. } else {
  859. // advance q
  860. if (lists[s] < 0) lists[s] = Math.Abs(q) * -1;
  861. else lists[s] = Math.Abs(q);
  862. s = q;
  863. q = lists[q];
  864. if (q > 0) continue;
  865. // Complete the sublist
  866. lists[s] = p;
  867. s = t;
  868. do {
  869. t = p;
  870. p = lists[p];
  871. } while (p > 0);
  872. }
  873. Debug.Assert(p <= 0);
  874. Debug.Assert(q <= 0);
  875. p *= -1;
  876. q *= -1;
  877. if (q == 0) {
  878. if (lists[s] < 0) lists[s] = Math.Abs(p) * -1;
  879. else lists[s] = Math.Abs(p);
  880. lists[t] = 0;
  881. // go back to new pass
  882. break;
  883. } // else keep going
  884. }
  885. }
  886. // use the resulting indices to
  887. // extract the order.
  888. object[] newData = new object[len];
  889. int start = lists[0];
  890. int outIndex = 0;
  891. while (start != 0) {
  892. newData[outIndex++] = sortData[start + index - 1];
  893. start = lists[start];
  894. }
  895. if (sortData.Length != count || index != 0) {
  896. for (int j = 0; j < count; j++) {
  897. sortData[j + index] = newData[j];
  898. }
  899. } else {
  900. sortData = newData;
  901. }
  902. return sortData;
  903. }
  904. /// <summary>
  905. /// Compares the two specified keys
  906. /// </summary>
  907. private bool DoCompare(object[] keys, IComparer cmp, int p, int q, bool reverse) {
  908. Debug.Assert(_data.Length == 0);
  909. int result = cmp.Compare(keys[p], keys[q]);
  910. bool ret = reverse ? (result >= 0) : (result <= 0);
  911. if (_data.Length != 0) throw PythonOps.ValueError("list mutated during sort");
  912. return ret;
  913. }
  914. internal int BinarySearch(int index, int count, object value, IComparer comparer) {
  915. lock (this) return Array.BinarySearch(_data, index, count, value, comparer);
  916. }
  917. internal bool EqualsWorker(List l) {
  918. using (new OrderedLocker(this, l)) {
  919. return PythonOps.ArraysEqual(_data, _size, l._data, l._size);
  920. }
  921. }
  922. internal int CompareToWorker(List l) {
  923. using (new OrderedLocker(this, l)) {
  924. return PythonOps.CompareArrays(_data, _size, l._data, l._size);
  925. }
  926. }
  927. internal bool FastSwap(int i, int j) {
  928. // ensure i <= j
  929. if (i > j) {
  930. int tmp = i;
  931. i = j;
  932. j = tmp;
  933. }
  934. // bounds checking
  935. if (i < 0 || j >= _size) {
  936. return false;
  937. } else if (i == j) {
  938. return true;
  939. }
  940. object temp = _data[i];
  941. _data[i] = _data[j];
  942. _data[j] = temp;
  943. return true;
  944. }
  945. #region IList Members
  946. bool IList.IsReadOnly {
  947. get { return false; }
  948. }
  949. public virtual object this[int index] {
  950. get {
  951. // no locks works here, we either return an
  952. // old item (as if we were called first) or return
  953. // a current item...
  954. // force reading the array first, _size can change after
  955. object[] data = GetData();
  956. return data[PythonOps.FixIndex(index, _size)];
  957. }
  958. set {
  959. // but we need a lock here incase we're assigning
  960. // while re-sizing.
  961. lock (this) _data[PythonOps.FixIndex(index, _size)] = value;
  962. }
  963. }
  964. public virtual object this[BigInteger index] {
  965. get {
  966. return this[index.ToInt32()];
  967. }
  968. set {
  969. this[index.ToInt32()] = value;
  970. }
  971. }
  972. /// <summary>
  973. /// Supports __index__ on arbitrary types, also prevents __float__
  974. /// </summary>
  975. public virtual object this[object index] {
  976. get {
  977. return this[Converter.ConvertToIndex(index)];
  978. }
  979. set {
  980. this[Converter.ConvertToIndex(index)] = value;
  981. }
  982. }
  983. [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
  984. private object[] GetData() {
  985. return _data;
  986. }
  987. [PythonHidden]
  988. public void RemoveAt(int index) {
  989. lock (this) RawDelete(index);
  990. }
  991. [PythonHidden]
  992. public bool Contains(object value) {
  993. return __contains__(value);
  994. }
  995. [PythonHidden]
  996. public void Clear() {
  997. lock (this) _size = 0;
  998. }
  999. [PythonHidden]
  1000. public int IndexOf(object value) {
  1001. // we get a stable view of the list, and if user code
  1002. // clears it then we'll stop iterating.
  1003. object[] locData;
  1004. int locSize;
  1005. lock (this) {
  1006. locData = _data;
  1007. locSize = _size;
  1008. }
  1009. for (int i = 0; i < Math.Min(locSize, _size); i++) {
  1010. if (PythonOps.EqualRetBool(locData[i], value)) return i;
  1011. }
  1012. return -1;
  1013. }
  1014. [PythonHidden]
  1015. public int Add(object value) {
  1016. lock (this) {
  1017. AddNoLock(value);
  1018. return _size - 1;
  1019. }
  1020. }
  1021. bool IList.IsFixedSize {
  1022. get { return false; }
  1023. }
  1024. #endregion
  1025. #region ICollection Members
  1026. bool ICollection.IsSynchronized {
  1027. get { return false; }
  1028. }
  1029. public int Count {
  1030. [PythonHidden]
  1031. get { return __len__(); }
  1032. }
  1033. [PythonHidden]
  1034. public void CopyTo(Array array, int index) {
  1035. Array.Copy(_data, 0, array, index, _size);
  1036. }
  1037. internal void CopyTo(Array array, int index, int arrayIndex, int count) {
  1038. Array.Copy(_data, index, array, arrayIndex, count);
  1039. }
  1040. object ICollection.SyncRoot {
  1041. get {
  1042. return this;
  1043. }
  1044. }
  1045. #endregion
  1046. #region IEnumerable Members
  1047. [PythonHidden]
  1048. public IEnumerator GetEnumerator() {
  1049. return __iter__();
  1050. }
  1051. #endregion
  1052. #region ICodeFormattable Members
  1053. public virtual string/*!*/ __repr__(CodeContext/*!*/ context) {
  1054. List<object> infinite = PythonOps.GetAndCheckInfinite(this);
  1055. if (infinite == null) {
  1056. return "[...]";
  1057. }
  1058. int index = infinite.Count;
  1059. infinite.Add(this);
  1060. try {
  1061. StringBuilder buf = new StringBuilder();
  1062. buf.Append("[");
  1063. for (int i = 0; i < _size; i++) {
  1064. if (i > 0) buf.Append(", ");
  1065. buf.Append(PythonOps.Repr(context, _data[i]));
  1066. }
  1067. buf.Append("]");
  1068. return buf.ToString();
  1069. } finally {
  1070. System.Diagnostics.Debug.Assert(index == infinite.Count - 1);
  1071. infinite.RemoveAt(index);
  1072. }
  1073. }
  1074. #endregion
  1075. #region IValueEquality Members
  1076. int IValueEquality.GetValueHashCode() {
  1077. throw PythonOps.TypeError("list object is unhashable");
  1078. }
  1079. bool IValueEquality.ValueEquals(object other) {
  1080. if (Object.ReferenceEquals(this, other)) return true;
  1081. List l = other as List;
  1082. if (l == null || l.__len__() != this.__len__()) return false;
  1083. return Equals(l);
  1084. }
  1085. #endregion
  1086. #region ICollection<object> Members
  1087. void ICollection<object>.Add(object item) {
  1088. append(item);
  1089. }
  1090. public void CopyTo(object[] array, int arrayIndex) {
  1091. for (int i = 0; i < __len__(); i++) {
  1092. array[arrayIndex + i] = this[i];
  1093. }
  1094. }
  1095. bool ICollection<object>.IsReadOnly {
  1096. get { return ((IList)this).IsReadOnly; }
  1097. }
  1098. [PythonHidden]
  1099. public bool Remove(object item) {
  1100. if (this.__contains__(item)) {
  1101. this.remove(item);
  1102. return true;
  1103. }
  1104. return false;
  1105. }
  1106. #endregion
  1107. #region IEnumerable<object> Members
  1108. IEnumerator<object> IEnumerable<object>.GetEnumerator() {
  1109. return new IEnumeratorOfTWrapper<object>(((IEnumerable)this).GetEnumerator());
  1110. }
  1111. #endregion
  1112. private bool Equals(List other) {
  1113. CompareUtil.Push(this, other);
  1114. try {
  1115. return EqualsWorker(other);
  1116. } finally {
  1117. CompareUtil.Pop(this, other);
  1118. }
  1119. }
  1120. internal int CompareTo(List other) {
  1121. CompareUtil.Push(this, other);
  1122. try {
  1123. return CompareToWorker(other);
  1124. } finally {
  1125. CompareUtil.Pop(this, other);
  1126. }
  1127. }
  1128. #region Rich Comparison Members
  1129. [return: MaybeNotImplemented]
  1130. public static object operator > (List self, object other) {
  1131. List l = other as List;
  1132. if (l == null) return NotImplementedType.Value;
  1133. return self.CompareTo(l) > 0 ? ScriptingRuntimeHelpers.True : ScriptingRuntimeHelpers.False;
  1134. }
  1135. [return: MaybeNotImplemented]
  1136. public static object operator <(List self, object other) {
  1137. List l = other as List;
  1138. if (l == null) return NotImplementedType.Value;
  1139. return self.CompareTo(l) < 0 ? ScriptingRuntimeHelpers.True : ScriptingRuntimeHelpers.False;
  1140. }
  1141. [return: MaybeNotImplemented]
  1142. public static object operator >=(List self, object other) {
  1143. List l = other as List;
  1144. if (l == null) return NotImplementedType.Value;
  1145. return self.CompareTo(l) >= 0 ? ScriptingRuntimeHelpers.True : ScriptingRuntimeHelpers.False;
  1146. }
  1147. [return: MaybeNotImplemented]
  1148. public static object operator <=(List self, object other) {
  1149. List l = other as List;
  1150. if (l == null) return NotImplementedType.Value;
  1151. return self.CompareTo(l) <= 0 ? ScriptingRuntimeHelpers.True : ScriptingRuntimeHelpers.False;
  1152. }
  1153. #endregion
  1154. }
  1155. [PythonType("listiterator")]
  1156. public sealed class ListIterator : IEnumerator, IEnumerable, IEnumerable<object>, IEnumerator<object> {
  1157. private int _index;
  1158. private readonly List _list;
  1159. private bool _iterating;
  1160. public ListIterator(List l) {
  1161. _list = l;
  1162. Reset();
  1163. }
  1164. #region IEnumerator Members
  1165. public void Reset() {
  1166. _index = -1;
  1167. _iterating = true;
  1168. }
  1169. public object Current {
  1170. get {
  1171. return _list._data[_index];
  1172. }
  1173. }
  1174. public bool MoveNext() {
  1175. if (_iterating) {
  1176. _index++;
  1177. _iterating = (_index < _list._size);
  1178. }
  1179. return _iterating;
  1180. }
  1181. #endregion
  1182. #region IEnumerable Members
  1183. public IEnumerator GetEnumerator() {
  1184. return this;
  1185. }
  1186. #endregion
  1187. #region IDisposable Members
  1188. public void Dispose() {
  1189. }
  1190. #endregion
  1191. #region IEnumerable<object> Members
  1192. IEnumerator<object> IEnumerable<object>.GetEnumerator() {
  1193. return this;
  1194. }
  1195. #endregion
  1196. }
  1197. [PythonType("listreverseiterator")]
  1198. public sealed class ListReverseIterator : IEnumerator, IEnumerable, IEnumerable<object>, IEnumerator<object> {
  1199. private int _index;
  1200. private readonly List _list;
  1201. private bool _iterating;
  1202. public ListReverseIterator(List l) {
  1203. _list = l;
  1204. Reset();
  1205. }
  1206. #region IEnumerator Members
  1207. public void Reset() {
  1208. _index = 0;
  1209. _iterating = true;
  1210. }
  1211. public object Current {
  1212. get {
  1213. return _list._data[_list._size - _index];
  1214. }
  1215. }
  1216. public bool MoveNext() {
  1217. if (_iterating) {
  1218. _index++;
  1219. _iterating = (_index <= _list._size);
  1220. }
  1221. return _iterating;
  1222. }
  1223. #endregion
  1224. #region IEnumerable Members
  1225. public IEnumerator GetEnumerator() {
  1226. return this;
  1227. }
  1228. #endregion
  1229. #region IDisposable Members
  1230. public void Dispose() {
  1231. }
  1232. #endregion
  1233. #region IEnumerable<object> Members
  1234. IEnumerator<object> IEnumerable<object>.GetEnumerator() {
  1235. return this;
  1236. }
  1237. #endregion
  1238. }
  1239. /// <summary>
  1240. /// we need to lock both objects (or copy all of one's data w/ it's lock held, and
  1241. /// then compare, which is bad). Therefore we have a strong order for locking on
  1242. /// the two objects based upon the hash code or object identity in case of a collision
  1243. /// </summary>
  1244. public struct OrderedLocker : IDisposable {
  1245. private readonly object _one, _two;
  1246. private bool _oneLocked,

Large files files are truncated, but you can click here to view the full file