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

/Languages/IronPython/IronPython.Modules/_collections.cs

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