PageRenderTime 75ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/DICK.B1/IronPython.Modules/_collections.cs

https://bitbucket.org/williamybs/uidipythontool
C# | 1014 lines | 795 code | 177 blank | 42 comment | 181 complexity | e6d36010be588ebe0190c45b7d1778c2 MD5 | raw 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.CompilerServices;
  20. using System.Text;
  21. using Microsoft.Scripting;
  22. using Microsoft.Scripting.Actions;
  23. using Microsoft.Scripting.Runtime;
  24. using Microsoft.Scripting.Utils;
  25. using IronPython.Runtime;
  26. using IronPython.Runtime.Binding;
  27. using IronPython.Runtime.Operations;
  28. using IronPython.Runtime.Types;
  29. #if CLR2
  30. using Microsoft.Scripting.Math;
  31. #else
  32. using System.Numerics;
  33. #endif
  34. using SpecialNameAttribute = System.Runtime.CompilerServices.SpecialNameAttribute;
  35. [assembly: PythonModule("_collections", typeof(IronPython.Modules.PythonCollections))]
  36. namespace IronPython.Modules {
  37. public class PythonCollections {
  38. public const string __doc__ = "High performance data structures\n";
  39. [PythonType]
  40. [DontMapIEnumerableToContains, DebuggerDisplay("deque, {__len__()} items"), DebuggerTypeProxy(typeof(CollectionDebugProxy))]
  41. public class deque : IEnumerable, IComparable, ICodeFormattable, IStructuralEquatable, IStructuralComparable, ICollection, IReversible
  42. #if CLR2
  43. , IValueEquality
  44. #endif
  45. {
  46. private object[] _data;
  47. private object _lockObj = new object();
  48. private int _head, _tail;
  49. private int _itemCnt, _maxLen, _version;
  50. public deque() {
  51. _maxLen = -1;
  52. clear();
  53. }
  54. // extra overloads just so that __init__ and __new__ are compatible and __new__ can accept any arguments
  55. public deque(object iterable)
  56. : this() {
  57. }
  58. public deque(object iterable, object maxLen)
  59. : this() {
  60. }
  61. public deque(params object[] args)
  62. : this() {
  63. }
  64. public deque([ParamDictionary]IDictionary<object, object> dict, params object[] args)
  65. : this() {
  66. }
  67. private deque(int maxLen) {
  68. // internal private constructor accepts maxlen < 0
  69. _maxLen = maxLen;
  70. clear();
  71. }
  72. public void __init__() {
  73. _maxLen = -1;
  74. clear();
  75. }
  76. public void __init__([ParamDictionary]IDictionary<object, object> dict) {
  77. _maxLen = VerifyMaxLen(dict);
  78. clear();
  79. }
  80. public void __init__(object iterable) {
  81. _maxLen = -1;
  82. clear();
  83. extend(iterable);
  84. }
  85. public void __init__(object iterable, object maxLen) {
  86. _maxLen = VerifyMaxLenValue(maxLen);
  87. clear();
  88. extend(iterable);
  89. }
  90. public void __init__(object iterable, [ParamDictionary]IDictionary<object, object> dict) {
  91. if (VerifyMaxLen(dict) < 0) {
  92. __init__(iterable);
  93. } else {
  94. __init__(iterable, VerifyMaxLen(dict));
  95. }
  96. }
  97. private static int VerifyMaxLen(IDictionary<object, object> dict) {
  98. if (dict.Count != 1) {
  99. throw PythonOps.TypeError("deque() takes at most 1 keyword argument ({0} given)", dict.Count);
  100. }
  101. object value;
  102. if (!dict.TryGetValue("maxlen", out value)) {
  103. IEnumerator<object> e = dict.Keys.GetEnumerator();
  104. if (e.MoveNext()) {
  105. throw PythonOps.TypeError("deque(): '{0}' is an invalid keyword argument", e.Current);
  106. }
  107. }
  108. return VerifyMaxLenValue(value);
  109. }
  110. private static int VerifyMaxLenValue(object value) {
  111. if (value == null) {
  112. return -1;
  113. } else if (value is int || value is BigInteger || value is double) {
  114. int val = (int)value;
  115. if (val < 0) throw PythonOps.ValueError("maxlen must be non-negative");
  116. return val;
  117. } else if (value is Extensible<int>) {
  118. int val = ((Extensible<int>)value).Value;
  119. if (val < 0) throw PythonOps.ValueError("maxlen must be non-negative");
  120. return val;
  121. }
  122. throw PythonOps.TypeError("deque(): keyword argument 'maxlen' requires integer");
  123. }
  124. #region core deque APIs
  125. public void append(object x) {
  126. lock (_lockObj) {
  127. _version++;
  128. // overwrite head if queue is at max length
  129. if (_itemCnt == _maxLen) {
  130. _data[_tail++] = x;
  131. if (_tail == _data.Length) {
  132. _tail = 0;
  133. }
  134. _head = _tail;
  135. return;
  136. }
  137. if (_itemCnt == _data.Length) {
  138. GrowArray();
  139. }
  140. _itemCnt++;
  141. _data[_tail++] = x;
  142. if (_tail == _data.Length) {
  143. _tail = 0;
  144. }
  145. }
  146. }
  147. public void appendleft(object x) {
  148. lock (_lockObj) {
  149. _version++;
  150. // overwrite tail if queue is full
  151. if (_itemCnt == _maxLen) {
  152. _head--;
  153. if (_head < 0) {
  154. _head = _data.Length - 1;
  155. }
  156. _tail = _head;
  157. _data[_head] = x;
  158. return;
  159. }
  160. if (_itemCnt == _data.Length) {
  161. GrowArray();
  162. }
  163. _itemCnt++;
  164. --_head;
  165. if (_head < 0) {
  166. _head = _data.Length - 1;
  167. }
  168. _data[_head] = x;
  169. }
  170. }
  171. public void clear() {
  172. lock (_lockObj) {
  173. _version++;
  174. _head = _tail = 0;
  175. _itemCnt = 0;
  176. if (_maxLen < 0) _data = new object[8];
  177. else _data = new object[Math.Min(_maxLen, 8)];
  178. }
  179. }
  180. public void extend(object iterable) {
  181. IEnumerator e = PythonOps.GetEnumerator(iterable);
  182. while (e.MoveNext()) {
  183. append(e.Current);
  184. }
  185. }
  186. public void extendleft(object iterable) {
  187. IEnumerator e = PythonOps.GetEnumerator(iterable);
  188. while (e.MoveNext()) {
  189. appendleft(e.Current);
  190. }
  191. }
  192. public object pop() {
  193. lock (_lockObj) {
  194. if (_itemCnt == 0) {
  195. throw PythonOps.IndexError("pop from an empty deque");
  196. }
  197. _version++;
  198. if (_tail != 0) {
  199. _tail--;
  200. } else {
  201. _tail = _data.Length - 1;
  202. }
  203. _itemCnt--;
  204. object res = _data[_tail];
  205. _data[_tail] = null;
  206. return res;
  207. }
  208. }
  209. public object popleft() {
  210. lock (_lockObj) {
  211. if (_itemCnt == 0) {
  212. throw PythonOps.IndexError("pop from an empty deque");
  213. }
  214. _version++;
  215. object res = _data[_head];
  216. _data[_head] = null;
  217. if (_head != _data.Length - 1) {
  218. _head++;
  219. } else {
  220. _head = 0;
  221. }
  222. _itemCnt--;
  223. return res;
  224. }
  225. }
  226. public void remove(object value) {
  227. lock (_lockObj) {
  228. int found = -1;
  229. int startVersion = _version;
  230. WalkDeque(delegate(int index) {
  231. if (PythonOps.EqualRetBool(_data[index], value)) {
  232. found = index;
  233. return false;
  234. }
  235. return true;
  236. });
  237. if (_version != startVersion) {
  238. throw PythonOps.IndexError("deque mutated during remove().");
  239. }
  240. if (found == _head) {
  241. popleft();
  242. } else if (found == (_tail > 0 ? _tail - 1 : _data.Length - 1)) {
  243. pop();
  244. } else if (found == -1) {
  245. throw PythonOps.ValueError("deque.remove(value): value not in deque");
  246. } else {
  247. // otherwise we're removing from the middle and need to slide the values over...
  248. _version++;
  249. int start;
  250. if (_head >= _tail) {
  251. start = 0;
  252. } else {
  253. start = _head;
  254. }
  255. bool finished = false;
  256. object copying = _tail != 0 ? _data[_tail - 1] : _data[_data.Length - 1];
  257. for (int i = _tail - 2; i >= start; i--) {
  258. object tmp = _data[i];
  259. _data[i] = copying;
  260. if (i == found) {
  261. finished = true;
  262. break;
  263. }
  264. copying = tmp;
  265. }
  266. if (_head >= _tail && !finished) {
  267. for (int i = _data.Length - 1; i >= _head; i--) {
  268. object tmp = _data[i];
  269. _data[i] = copying;
  270. if (i == found) break;
  271. copying = tmp;
  272. }
  273. }
  274. // we're one smaller now
  275. _tail--;
  276. _itemCnt--;
  277. if (_tail < 0) {
  278. // and tail just wrapped to the beginning
  279. _tail = _data.Length - 1;
  280. }
  281. }
  282. }
  283. }
  284. public void rotate(CodeContext/*!*/ context) {
  285. rotate(context, 1);
  286. }
  287. public void rotate(CodeContext/*!*/ context, object n) {
  288. lock (_lockObj) {
  289. // rotation is easy if we have no items!
  290. if (_itemCnt == 0) return;
  291. // set rot to the appropriate positive int
  292. int rot = PythonContext.GetContext(context).ConvertToInt32(n) % _itemCnt;
  293. rot = rot % _itemCnt;
  294. if (rot == 0) return; // no need to rotate if we'll end back up where we started
  295. if (rot < 0) rot += _itemCnt;
  296. _version++;
  297. if (_itemCnt == _data.Length) {
  298. // if all indices are filled no moves are required
  299. _head = _tail = (_tail - rot + _data.Length) % _data.Length;
  300. } else {
  301. // too bad, we got gaps, looks like we'll be doing some real work.
  302. object[] newData = new object[_itemCnt]; // we re-size to itemCnt so that future rotates don't require work
  303. int curWriteIndex = rot;
  304. WalkDeque(delegate(int curIndex) {
  305. newData[curWriteIndex] = _data[curIndex];
  306. curWriteIndex = (curWriteIndex + 1) % _itemCnt;
  307. return true;
  308. });
  309. _head = _tail = 0;
  310. _data = newData;
  311. }
  312. }
  313. }
  314. public object this[CodeContext/*!*/ context, object index] {
  315. get {
  316. lock (_lockObj) {
  317. return _data[IndexToSlot(context, index)];
  318. }
  319. }
  320. set {
  321. lock (_lockObj) {
  322. _version++;
  323. _data[IndexToSlot(context, index)] = value;
  324. }
  325. }
  326. }
  327. #endregion
  328. public object __copy__(CodeContext/*!*/ context) {
  329. if (GetType() == typeof(deque)) {
  330. deque res = new deque(_maxLen);
  331. res.extend(((IEnumerable)this).GetEnumerator());
  332. return res;
  333. } else {
  334. return PythonCalls.Call(context, DynamicHelpers.GetPythonType(this), ((IEnumerable)this).GetEnumerator());
  335. }
  336. }
  337. public void __delitem__(CodeContext/*!*/ context, object index) {
  338. lock (_lockObj) {
  339. int realIndex = IndexToSlot(context, index);
  340. _version++;
  341. if (realIndex == _head) {
  342. popleft();
  343. } else if (realIndex == (_tail - 1) ||
  344. (realIndex == (_data.Length - 1) && _tail == _data.Length)) {
  345. pop();
  346. } else {
  347. // we're removing an index from the middle, what a pain...
  348. // we'll just recreate our data by walking the data once.
  349. object[] newData = new object[_data.Length];
  350. int writeIndex = 0;
  351. WalkDeque(delegate(int curIndex) {
  352. if (curIndex != realIndex) {
  353. newData[writeIndex++] = _data[curIndex];
  354. }
  355. return true;
  356. });
  357. _head = 0;
  358. _tail = writeIndex;
  359. _data = newData;
  360. _itemCnt--;
  361. }
  362. }
  363. }
  364. public PythonTuple __reduce__() {
  365. lock (_lockObj) {
  366. object[] items = new object[_itemCnt];
  367. int curItem = 0;
  368. WalkDeque(delegate(int curIndex) {
  369. items[curItem++] = _data[curIndex];
  370. return true;
  371. });
  372. return PythonTuple.MakeTuple(
  373. DynamicHelpers.GetPythonTypeFromType(GetType()),
  374. PythonTuple.MakeTuple(List.FromArrayNoCopy(items)),
  375. null
  376. );
  377. }
  378. }
  379. public int __len__() {
  380. return _itemCnt;
  381. }
  382. #region IComparable Members
  383. int IComparable.CompareTo(object obj) {
  384. deque otherDeque = obj as deque;
  385. if (otherDeque == null) {
  386. throw new ArgumentException("expected deque");
  387. }
  388. return CompareToWorker(otherDeque);
  389. }
  390. private int CompareToWorker(deque otherDeque) {
  391. return CompareToWorker(otherDeque, null);
  392. }
  393. private int CompareToWorker(deque otherDeque, IComparer comparer) {
  394. Assert.NotNull(otherDeque);
  395. if (otherDeque._itemCnt == 0 && _itemCnt == 0) {
  396. // comparing two empty deques
  397. return 0;
  398. }
  399. if (CompareUtil.Check(this)) return 0;
  400. CompareUtil.Push(this);
  401. try {
  402. int otherIndex = otherDeque._head, ourIndex = _head;
  403. for (; ; ) {
  404. int result;
  405. if (comparer == null) {
  406. result = PythonOps.Compare(_data[ourIndex], otherDeque._data[otherIndex]);
  407. } else {
  408. result = comparer.Compare(_data[ourIndex], otherDeque._data[otherIndex]);
  409. }
  410. if (result != 0) {
  411. return result;
  412. }
  413. // advance both indexes
  414. otherIndex++;
  415. if (otherIndex == otherDeque._data.Length) {
  416. otherIndex = 0;
  417. }
  418. if (otherIndex == otherDeque._tail) {
  419. break;
  420. }
  421. ourIndex++;
  422. if (ourIndex == _data.Length) {
  423. ourIndex = 0;
  424. }
  425. if (ourIndex == _tail) {
  426. break;
  427. }
  428. }
  429. // all items are equal, but # of items may be different.
  430. if (otherDeque._itemCnt == _itemCnt) {
  431. // same # of items, all items are equal
  432. return 0;
  433. }
  434. return _itemCnt > otherDeque._itemCnt ? 1 : -1;
  435. } finally {
  436. CompareUtil.Pop(this);
  437. }
  438. }
  439. #endregion
  440. #region IStructuralComparable Members
  441. int IStructuralComparable.CompareTo(object other, IComparer comparer) {
  442. deque otherDeque = other as deque;
  443. if (otherDeque == null) {
  444. throw new ArgumentException("expected deque");
  445. }
  446. return CompareToWorker(otherDeque, comparer);
  447. }
  448. #endregion
  449. #region IEnumerable Members
  450. IEnumerator IEnumerable.GetEnumerator() {
  451. return new DequeIterator(this);
  452. }
  453. [PythonType("deque_iterator")]
  454. private sealed class DequeIterator : IEnumerable, IEnumerator {
  455. private readonly deque _deque;
  456. private int _curIndex, _moveCnt, _version;
  457. public DequeIterator(deque d) {
  458. lock (d._lockObj) {
  459. _deque = d;
  460. _curIndex = d._head - 1;
  461. _version = d._version;
  462. }
  463. }
  464. #region IEnumerator Members
  465. object IEnumerator.Current {
  466. get {
  467. return _deque._data[_curIndex];
  468. }
  469. }
  470. bool IEnumerator.MoveNext() {
  471. lock (_deque._lockObj) {
  472. if (_version != _deque._version) {
  473. throw PythonOps.RuntimeError("deque mutated during iteration");
  474. }
  475. if (_moveCnt < _deque._itemCnt) {
  476. _curIndex++;
  477. _moveCnt++;
  478. if (_curIndex == _deque._data.Length) {
  479. _curIndex = 0;
  480. }
  481. return true;
  482. }
  483. return false;
  484. }
  485. }
  486. void IEnumerator.Reset() {
  487. _moveCnt = 0;
  488. _curIndex = _deque._head - 1;
  489. }
  490. #endregion
  491. #region IEnumerable Members
  492. public IEnumerator GetEnumerator() {
  493. return this;
  494. }
  495. #endregion
  496. }
  497. #endregion
  498. #region __reverse__ implementation
  499. public virtual IEnumerator __reversed__() {
  500. return new deque_reverse_iterator(this);
  501. }
  502. [PythonType]
  503. private class deque_reverse_iterator : IEnumerator {
  504. private readonly deque _deque;
  505. private int _curIndex, _moveCnt, _version;
  506. public deque_reverse_iterator(deque d) {
  507. lock (d._lockObj) {
  508. _deque = d;
  509. _curIndex = d._tail;
  510. _version = d._version;
  511. }
  512. }
  513. #region IEnumerator Members
  514. object IEnumerator.Current {
  515. get {
  516. return _deque._data[_curIndex];
  517. }
  518. }
  519. bool IEnumerator.MoveNext() {
  520. lock (_deque._lockObj) {
  521. if (_version != _deque._version) {
  522. throw PythonOps.RuntimeError("deque mutated during iteration");
  523. }
  524. if (_moveCnt < _deque._itemCnt) {
  525. _curIndex--;
  526. _moveCnt++;
  527. if (_curIndex < 0) {
  528. _curIndex = _deque._data.Length - 1;
  529. }
  530. return true;
  531. }
  532. return false;
  533. }
  534. }
  535. void IEnumerator.Reset() {
  536. _moveCnt = 0;
  537. _curIndex = _deque._tail;
  538. }
  539. #endregion
  540. }
  541. #endregion
  542. #region private members
  543. private void GrowArray() {
  544. // do nothing if array is already at its max length
  545. if (_data.Length == _maxLen) return;
  546. object[] newData;
  547. if (_maxLen < 0) newData = new object[_data.Length * 2];
  548. else newData = new object[Math.Min(_maxLen, _data.Length * 2)];
  549. // make the array completely sequential again
  550. // by starting head back at 0.
  551. int cnt1, cnt2;
  552. if (_head >= _tail) {
  553. cnt1 = _data.Length - _head;
  554. cnt2 = _data.Length - cnt1;
  555. } else {
  556. cnt1 = _tail - _head;
  557. cnt2 = _data.Length - cnt1;
  558. }
  559. Array.Copy(_data, _head, newData, 0, cnt1);
  560. Array.Copy(_data, 0, newData, cnt1, cnt2);
  561. _head = 0;
  562. _tail = _data.Length;
  563. _data = newData;
  564. }
  565. private int IndexToSlot(CodeContext/*!*/ context, object index) {
  566. if (_itemCnt == 0) {
  567. throw PythonOps.IndexError("deque index out of range");
  568. }
  569. int intIndex = PythonContext.GetContext(context).ConvertToInt32(index);
  570. if (intIndex >= 0) {
  571. if (intIndex >= _itemCnt) {
  572. throw PythonOps.IndexError("deque index out of range");
  573. }
  574. int realIndex = _head + intIndex;
  575. if (realIndex >= _data.Length) {
  576. realIndex -= _data.Length;
  577. }
  578. return realIndex;
  579. } else {
  580. if ((intIndex * -1) > _itemCnt) {
  581. throw PythonOps.IndexError("deque index out of range");
  582. }
  583. int realIndex = _tail + intIndex;
  584. if (realIndex < 0) {
  585. realIndex += _data.Length;
  586. }
  587. return realIndex;
  588. }
  589. }
  590. private delegate bool DequeWalker(int curIndex);
  591. /// <summary>
  592. /// Walks the queue calling back to the specified delegate for
  593. /// each populated index in the queue.
  594. /// </summary>
  595. private void WalkDeque(DequeWalker walker) {
  596. if (_itemCnt != 0) {
  597. int end;
  598. if (_head >= _tail) {
  599. end = _data.Length;
  600. } else {
  601. end = _tail;
  602. }
  603. for (int i = _head; i < end; i++) {
  604. if (!walker(i)) {
  605. return;
  606. }
  607. }
  608. if (_head >= _tail) {
  609. for (int i = 0; i < _tail; i++) {
  610. if (!walker(i)) {
  611. return;
  612. }
  613. }
  614. }
  615. }
  616. }
  617. #endregion
  618. #region ICodeFormattable Members
  619. public virtual string/*!*/ __repr__(CodeContext/*!*/ context) {
  620. List<object> infinite = PythonOps.GetAndCheckInfinite(this);
  621. if (infinite == null) {
  622. return "[...]";
  623. }
  624. int infiniteIndex = infinite.Count;
  625. infinite.Add(this);
  626. try {
  627. StringBuilder sb = new StringBuilder();
  628. sb.Append("deque([");
  629. string comma = "";
  630. lock (_lockObj) {
  631. WalkDeque(delegate(int index) {
  632. sb.Append(comma);
  633. sb.Append(PythonOps.Repr(context, _data[index]));
  634. comma = ", ";
  635. return true;
  636. });
  637. }
  638. if (_maxLen < 0) {
  639. sb.Append("])");
  640. } else {
  641. sb.Append("], maxlen=");
  642. sb.Append(_maxLen);
  643. sb.Append(')');
  644. }
  645. return sb.ToString();
  646. } finally {
  647. System.Diagnostics.Debug.Assert(infiniteIndex == infinite.Count - 1);
  648. infinite.RemoveAt(infiniteIndex);
  649. }
  650. }
  651. #endregion
  652. #region IValueEquality Members
  653. #if CLR2
  654. int IValueEquality.GetValueHashCode() {
  655. throw PythonOps.TypeError("deque objects are unhashable");
  656. }
  657. bool IValueEquality.ValueEquals(object other) {
  658. if (!(other is deque)) return false;
  659. return EqualsWorker((deque)other);
  660. }
  661. #endif
  662. #endregion
  663. #region IStructuralEquatable Members
  664. public const object __hash__ = null;
  665. int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) {
  666. if (CompareUtil.Check(this)) {
  667. return 0;
  668. }
  669. int res;
  670. CompareUtil.Push(this);
  671. try {
  672. res = ((IStructuralEquatable)new PythonTuple(this)).GetHashCode(comparer);
  673. } finally {
  674. CompareUtil.Pop(this);
  675. }
  676. return res;
  677. }
  678. bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) {
  679. if (!(other is deque)) return false;
  680. return EqualsWorker((deque)other, comparer);
  681. }
  682. private bool EqualsWorker(deque other) {
  683. return EqualsWorker(other, null);
  684. }
  685. private bool EqualsWorker(deque otherDeque, IEqualityComparer comparer) {
  686. Assert.NotNull(otherDeque);
  687. if (otherDeque._itemCnt != _itemCnt) {
  688. // number of items is different, deques can't be equal
  689. return false;
  690. } else if (otherDeque._itemCnt == 0) {
  691. // two empty deques are equal
  692. return true;
  693. }
  694. if (CompareUtil.Check(this)) return true;
  695. CompareUtil.Push(this);
  696. try {
  697. for (int otherIndex = otherDeque._head, ourIndex = _head; ourIndex != _tail; ) {
  698. bool result;
  699. if (comparer == null) {
  700. result = PythonOps.EqualRetBool(_data[ourIndex], otherDeque._data[otherIndex]);
  701. } else {
  702. result = comparer.Equals(_data[ourIndex], otherDeque._data[otherIndex]);
  703. }
  704. if (!result) {
  705. return false;
  706. }
  707. // advance both indices
  708. otherIndex++;
  709. if (otherIndex == otherDeque._data.Length) {
  710. otherIndex = 0;
  711. }
  712. ourIndex++;
  713. if (ourIndex == _data.Length) {
  714. ourIndex = 0;
  715. }
  716. }
  717. // same # of items, all items are equal
  718. return true;
  719. } finally {
  720. CompareUtil.Pop(this);
  721. }
  722. }
  723. #endregion
  724. #region Rich Comparison Members
  725. [SpecialName]
  726. [return: MaybeNotImplemented]
  727. public static object operator >(deque self, object other) {
  728. deque otherDeque = other as deque;
  729. if (otherDeque == null) return NotImplementedType.Value;
  730. return ScriptingRuntimeHelpers.BooleanToObject(self.CompareToWorker(otherDeque) > 0);
  731. }
  732. [SpecialName]
  733. [return: MaybeNotImplemented]
  734. public static object operator <(deque self, object other) {
  735. deque otherDeque = other as deque;
  736. if (otherDeque == null) return NotImplementedType.Value;
  737. return ScriptingRuntimeHelpers.BooleanToObject(self.CompareToWorker(otherDeque) < 0);
  738. }
  739. [SpecialName]
  740. [return: MaybeNotImplemented]
  741. public static object operator >=(deque self, object other) {
  742. deque otherDeque = other as deque;
  743. if (otherDeque == null) return NotImplementedType.Value;
  744. return ScriptingRuntimeHelpers.BooleanToObject(self.CompareToWorker(otherDeque) >= 0);
  745. }
  746. [SpecialName]
  747. [return: MaybeNotImplemented]
  748. public static object operator <=(deque self, object other) {
  749. deque otherDeque = other as deque;
  750. if (otherDeque == null) return NotImplementedType.Value;
  751. return ScriptingRuntimeHelpers.BooleanToObject(self.CompareToWorker(otherDeque) <= 0);
  752. }
  753. #endregion
  754. #region ICollection Members
  755. void ICollection.CopyTo(Array array, int index) {
  756. int i = 0;
  757. foreach (object o in this) {
  758. array.SetValue(o, index + i++);
  759. }
  760. }
  761. int ICollection.Count {
  762. get { return this._itemCnt; }
  763. }
  764. bool ICollection.IsSynchronized {
  765. get { return false; }
  766. }
  767. object ICollection.SyncRoot {
  768. get { return this; }
  769. }
  770. #endregion
  771. }
  772. [PythonType]
  773. public class defaultdict : PythonDictionary {
  774. private object _factory;
  775. private CallSite<Func<CallSite, CodeContext, object, object>> _missingSite;
  776. public defaultdict(CodeContext/*!*/ context) {
  777. _missingSite = CallSite<Func<CallSite, CodeContext, object, object>>.Create(
  778. new PythonInvokeBinder(
  779. PythonContext.GetContext(context),
  780. new CallSignature(0)
  781. )
  782. );
  783. }
  784. public void __init__(object default_factory) {
  785. _factory = default_factory;
  786. }
  787. public void __init__(CodeContext/*!*/ context, object default_factory, params object[] args) {
  788. _factory = default_factory;
  789. foreach (object o in args) {
  790. update(context, o);
  791. }
  792. }
  793. public void __init__(CodeContext/*!*/ context, object default_factory, [ParamDictionary]IDictionary<object, object> dict, params object[] args) {
  794. __init__(context, default_factory, args);
  795. foreach (KeyValuePair<object , object> kvp in dict) {
  796. this[kvp.Key] = kvp.Value;
  797. }
  798. }
  799. public object default_factory {
  800. get {
  801. return _factory;
  802. }
  803. set {
  804. _factory = value;
  805. }
  806. }
  807. public object __missing__(CodeContext context, object key) {
  808. object factory = _factory;
  809. if (factory == null) {
  810. throw PythonOps.KeyError(key);
  811. }
  812. return this[key] = _missingSite.Target.Invoke(_missingSite, context, factory);
  813. }
  814. public object __copy__(CodeContext/*!*/ context) {
  815. return copy(context);
  816. }
  817. public override PythonDictionary copy(CodeContext/*!*/ context) {
  818. defaultdict res = new defaultdict(context);
  819. res.default_factory = this.default_factory;
  820. res.update(context, this);
  821. return res;
  822. }
  823. public override string __repr__(CodeContext context) {
  824. return String.Format("defaultdict({0}, {1})", PythonOps.Repr(context, default_factory), base.__repr__(context));
  825. }
  826. public PythonTuple __reduce__() {
  827. return PythonTuple.MakeTuple(
  828. DynamicHelpers.GetPythonType(this),
  829. PythonTuple.MakeTuple(default_factory),
  830. null,
  831. null,
  832. iteritems()
  833. );
  834. }
  835. }
  836. }
  837. }