PageRenderTime 66ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/IronPython_2_0/Src/IronPython/Runtime/List.cs

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