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

/IronPython_2_6/Src/IronPython/Runtime/List.cs

#
C# | 1650 lines | 1225 code | 304 blank | 121 comment | 225 complexity | 83bf74a9fd705252588debae6ceafabb 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

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

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