PageRenderTime 48ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/Languages/IronPython/IronPython.Modules/array.cs

http://github.com/IronLanguages/main
C# | 1324 lines | 1072 code | 221 blank | 31 comment | 200 complexity | a303f40759e1f3f59863e9752200f98f MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception

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

  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the 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.IO;
  20. using System.Runtime.InteropServices;
  21. using System.Text;
  22. using IronPython.Runtime;
  23. using IronPython.Runtime.Operations;
  24. using IronPython.Runtime.Types;
  25. using Microsoft.Scripting;
  26. using Microsoft.Scripting.Runtime;
  27. using Microsoft.Scripting.Utils;
  28. using SpecialName = System.Runtime.CompilerServices.SpecialNameAttribute;
  29. using System.Reflection;
  30. #if FEATURE_NUMERICS
  31. using System.Numerics;
  32. #else
  33. using Microsoft.Scripting.Math;
  34. #endif
  35. [assembly: PythonModule("array", typeof(IronPython.Modules.ArrayModule))]
  36. namespace IronPython.Modules {
  37. public static class ArrayModule {
  38. public const string __doc__ = "Provides arrays for native data types. These can be used for compact storage or native interop via ctypes";
  39. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
  40. public static readonly PythonType/*!*/ ArrayType = DynamicHelpers.GetPythonTypeFromType(typeof(array));
  41. [PythonType]
  42. public class array : IPythonArray, IEnumerable, IWeakReferenceable, ICollection, ICodeFormattable, IList<object>, IStructuralEquatable
  43. #if CLR2
  44. , IValueEquality
  45. #endif
  46. {
  47. private ArrayData _data;
  48. private char _typeCode;
  49. private WeakRefTracker _tracker;
  50. public array([BytesConversion]string type, [Optional]object initializer) {
  51. if (type == null || type.Length != 1) {
  52. throw PythonOps.TypeError("expected character, got {0}", PythonTypeOps.GetName(type));
  53. }
  54. _typeCode = type[0];
  55. _data = CreateData(_typeCode);
  56. if (initializer != Missing.Value) extend(initializer);
  57. }
  58. private array(char typeCode, ArrayData data) {
  59. _typeCode = typeCode;
  60. _data = data;
  61. }
  62. private static ArrayData CreateData(char typecode) {
  63. ArrayData data;
  64. switch (typecode) {
  65. case 'c': data = new ArrayData<char>(); break;
  66. case 'b': data = new ArrayData<sbyte>(); break;
  67. case 'B': data = new ArrayData<byte>(); break;
  68. case 'u': data = new ArrayData<char>(); break;
  69. case 'h': data = new ArrayData<short>(); break;
  70. case 'H': data = new ArrayData<ushort>(); break;
  71. case 'l':
  72. case 'i': data = new ArrayData<int>(); break;
  73. case 'L':
  74. case 'I': data = new ArrayData<uint>(); break;
  75. case 'f': data = new ArrayData<float>(); break;
  76. case 'd': data = new ArrayData<double>(); break;
  77. default:
  78. throw PythonOps.ValueError("Bad type code (expected one of 'c', 'b', 'B', 'u', 'H', 'h', 'i', 'I', 'l', 'L', 'f', 'd')");
  79. }
  80. return data;
  81. }
  82. [SpecialName]
  83. public array InPlaceAdd(array other) {
  84. if (typecode != other.typecode) throw PythonOps.TypeError("cannot add different typecodes");
  85. if (other._data.Length != 0) {
  86. extend(other);
  87. }
  88. return this;
  89. }
  90. public static array operator +(array self, array other) {
  91. if (self.typecode != other.typecode) throw PythonOps.TypeError("cannot add different typecodes");
  92. array res = new array(self.typecode, Missing.Value);
  93. foreach (object o in self) {
  94. res.append(o);
  95. }
  96. foreach (object o in other) {
  97. res.append(o);
  98. }
  99. return res;
  100. }
  101. [SpecialName]
  102. public array InPlaceMultiply(int value) {
  103. if (value <= 0) {
  104. _data.Clear();
  105. } else {
  106. List myData = tolist();
  107. for (int i = 0; i < (value - 1); i++) {
  108. extend(myData);
  109. }
  110. }
  111. return this;
  112. }
  113. public static array operator *(array array, int value) {
  114. if ((BigInteger)value * array.__len__() * array.itemsize > SysModule.maxsize) {
  115. throw PythonOps.MemoryError("");
  116. }
  117. if (value <= 0) {
  118. return new array(array.typecode, Missing.Value);
  119. }
  120. return new array(array._typeCode, array._data.Multiply(value));
  121. }
  122. public static array operator *(array array, BigInteger value) {
  123. int intValue;
  124. if (!value.AsInt32(out intValue)) {
  125. throw PythonOps.OverflowError("cannot fit 'long' into an index-sized integer");
  126. } else if (value * array.__len__() * array.itemsize > SysModule.maxsize) {
  127. throw PythonOps.MemoryError("");
  128. }
  129. return array * intValue;
  130. }
  131. public static array operator *(int value, array array) {
  132. return array * value;
  133. }
  134. public static array operator *(BigInteger value, array array) {
  135. return array * value;
  136. }
  137. public void append(object iterable) {
  138. _data.Append(iterable);
  139. }
  140. internal IntPtr GetArrayAddress() {
  141. return _data.GetAddress();
  142. }
  143. public PythonTuple buffer_info() {
  144. return PythonTuple.MakeTuple(
  145. _data.GetAddress().ToPython(),
  146. _data.Length
  147. );
  148. }
  149. public void byteswap() {
  150. Stream s = ToStream();
  151. byte[] bytes = new byte[s.Length];
  152. s.Read(bytes, 0, bytes.Length);
  153. byte[] tmp = new byte[itemsize];
  154. for (int i = 0; i < bytes.Length; i += itemsize) {
  155. for (int j = 0; j < itemsize; j++) {
  156. tmp[j] = bytes[i + j];
  157. }
  158. for (int j = 0; j < itemsize; j++) {
  159. bytes[i + j] = tmp[itemsize - (j + 1)];
  160. }
  161. }
  162. _data.Clear();
  163. MemoryStream ms = new MemoryStream(bytes);
  164. FromStream(ms);
  165. }
  166. public int count(object x) {
  167. if (x == null) return 0;
  168. return _data.Count(x);
  169. }
  170. public void extend(object iterable) {
  171. array pa = iterable as array;
  172. if (pa != null) {
  173. if (typecode != pa.typecode) {
  174. throw PythonOps.TypeError("cannot extend with different typecode");
  175. }
  176. int l = pa._data.Length;
  177. for (int i = 0; i < l; i++) {
  178. _data.Append(pa._data.GetData(i));
  179. }
  180. return;
  181. }
  182. string str = iterable as string;
  183. if (str != null && _typeCode != 'u') {
  184. fromstring(str);
  185. return;
  186. }
  187. Bytes bytes = iterable as Bytes;
  188. if (bytes != null) {
  189. fromstring(bytes);
  190. return;
  191. }
  192. PythonBuffer buf = iterable as PythonBuffer;
  193. if (buf != null) {
  194. fromstring(buf);
  195. return;
  196. }
  197. IEnumerator ie = PythonOps.GetEnumerator(iterable);
  198. while (ie.MoveNext()) {
  199. append(ie.Current);
  200. }
  201. }
  202. public void fromlist(object iterable) {
  203. IEnumerator ie = PythonOps.GetEnumerator(iterable);
  204. List<object> items = new List<object>();
  205. while (ie.MoveNext()) {
  206. if (!_data.CanStore(ie.Current)) {
  207. throw PythonOps.TypeError("expected {0}, got {1}",
  208. DynamicHelpers.GetPythonTypeFromType(_data.StorageType).Name,
  209. DynamicHelpers.GetPythonType(ie.Current).Name);
  210. }
  211. items.Add(ie.Current);
  212. }
  213. extend(items);
  214. }
  215. public void fromfile(PythonFile f, int n) {
  216. int bytesNeeded = n * itemsize;
  217. string bytes = f.read(bytesNeeded);
  218. if (bytes.Length < bytesNeeded) throw PythonOps.EofError("file not large enough");
  219. fromstring(bytes);
  220. }
  221. public void fromstring([NotNull]Bytes b) {
  222. if ((b.Count % itemsize) != 0) throw PythonOps.ValueError("string length not a multiple of itemsize");
  223. FromStream(new MemoryStream(b._bytes, false));
  224. }
  225. public void fromstring([NotNull]string s) {
  226. if ((s.Length % itemsize) != 0) throw PythonOps.ValueError("string length not a multiple of itemsize");
  227. byte[] bytes = new byte[s.Length];
  228. for (int i = 0; i < bytes.Length; i++) {
  229. bytes[i] = checked((byte)s[i]);
  230. }
  231. MemoryStream ms = new MemoryStream(bytes);
  232. FromStream(ms);
  233. }
  234. public void fromstring([NotNull]PythonBuffer buf) {
  235. if ((buf.Size % itemsize) != 0) throw PythonOps.ValueError("string length not a multiple of itemsize");
  236. FromStream(new MemoryStream(buf.byteCache, false));
  237. }
  238. public void fromunicode(CodeContext/*!*/ context, string s) {
  239. if (s == null) {
  240. throw PythonOps.TypeError("expected string");
  241. } else if (_typeCode != 'u') {
  242. throw PythonOps.ValueError("fromunicode() may only be called on type 'u' arrays");
  243. }
  244. ArrayData<char> data = (ArrayData<char>)_data;
  245. data.EnsureSize(data.Length + s.Length);
  246. for (int i = 0; i < s.Length; i++) {
  247. data.Data[i + data.Length] = s[i];
  248. }
  249. data.Length += s.Length;
  250. }
  251. public int index(object x) {
  252. if (x == null) throw PythonOps.ValueError("got None, expected value");
  253. int res = _data.Index(x);
  254. if (res == -1) throw PythonOps.ValueError("x not found");
  255. return res;
  256. }
  257. public void insert(int i, object x) {
  258. if (i > _data.Length) i = _data.Length;
  259. if (i < 0) i = _data.Length + i;
  260. if (i < 0) i = 0;
  261. _data.Insert(i, x);
  262. }
  263. public int itemsize {
  264. get {
  265. switch (_typeCode) {
  266. case 'c': // char
  267. case 'b': // signed byte
  268. case 'B': // unsigned byte
  269. case 'x': // pad byte
  270. case 's': // null-terminated string
  271. case 'p': // Pascal string
  272. return 1;
  273. case 'u': // unicode char
  274. case 'h': // signed short
  275. case 'H': // unsigned short
  276. return 2;
  277. case 'i': // signed int
  278. case 'I': // unsigned int
  279. case 'l': // signed long
  280. case 'L': // unsigned long
  281. case 'f': // float
  282. return 4;
  283. case 'P': // pointer
  284. return IntPtr.Size;
  285. case 'q': // signed long long
  286. case 'Q': // unsigned long long
  287. case 'd': // double
  288. return 8;
  289. default:
  290. return 0;
  291. }
  292. }
  293. }
  294. public object pop() {
  295. return pop(-1);
  296. }
  297. public object pop(int i) {
  298. i = PythonOps.FixIndex(i, _data.Length);
  299. object res = _data.GetData(i);
  300. _data.RemoveAt(i);
  301. return res;
  302. }
  303. [Python3Warning("array.read() not supported in 3.x; use array.fromfile()")]
  304. public void read(PythonFile f, int n) {
  305. fromfile(f, n);
  306. }
  307. public void remove(object value) {
  308. if (value == null) throw PythonOps.ValueError("got None, expected value");
  309. _data.Remove(value);
  310. }
  311. public void reverse() {
  312. for (int index = 0; index < _data.Length / 2; index++) {
  313. int left = index, right = _data.Length - (index + 1);
  314. Debug.Assert(left != right);
  315. _data.Swap(left, right);
  316. }
  317. }
  318. public virtual object this[int index] {
  319. get {
  320. object val = _data.GetData(PythonOps.FixIndex(index, _data.Length));
  321. switch (_typeCode) {
  322. case 'b': return (int)(sbyte)val;
  323. case 'B': return (int)(byte)val;
  324. case 'c':
  325. case 'u': return new string((char)val, 1);
  326. case 'h': return (int)(short)val;
  327. case 'H': return (int)(ushort)val;
  328. case 'l': return val;
  329. case 'i': return val;
  330. case 'L': return (BigInteger)(uint)val;
  331. case 'I':
  332. return (BigInteger)(uint)val;
  333. case 'f': return (double)(float)val;
  334. case 'd': return val;
  335. default:
  336. throw PythonOps.ValueError("Bad type code (expected one of 'c', 'b', 'B', 'u', 'H', 'h', 'i', 'I', 'l', 'L', 'f', 'd')");
  337. }
  338. }
  339. set {
  340. _data.SetData(PythonOps.FixIndex(index, _data.Length), value);
  341. }
  342. }
  343. internal byte[] RawGetItem(int index) {
  344. MemoryStream ms = new MemoryStream();
  345. BinaryWriter bw = new BinaryWriter(ms);
  346. switch (_typeCode) {
  347. case 'c': bw.Write((byte)(char)_data.GetData(index)); break;
  348. case 'b': bw.Write((sbyte)_data.GetData(index)); break;
  349. case 'B': bw.Write((byte)_data.GetData(index)); break;
  350. case 'u': bw.Write((char)_data.GetData(index)); break;
  351. case 'h': bw.Write((short)_data.GetData(index)); break;
  352. case 'H': bw.Write((ushort)_data.GetData(index)); break;
  353. case 'l':
  354. case 'i': bw.Write((int)_data.GetData(index)); break;
  355. case 'L':
  356. case 'I': bw.Write((uint)_data.GetData(index)); break;
  357. case 'f': bw.Write((float)_data.GetData(index)); break;
  358. case 'd': bw.Write((double)_data.GetData(index)); break;
  359. }
  360. return ms.ToArray();
  361. }
  362. public void __delitem__(int index) {
  363. _data.RemoveAt(PythonOps.FixIndex(index, _data.Length));
  364. }
  365. public void __delitem__(Slice slice) {
  366. if (slice == null) throw PythonOps.TypeError("expected Slice, got None");
  367. int start, stop, step;
  368. // slice is sealed, indices can't be user code...
  369. slice.indices(_data.Length, out start, out stop, out step);
  370. if (step > 0 && (start >= stop)) return;
  371. if (step < 0 && (start <= stop)) return;
  372. if (step == 1) {
  373. int i = start;
  374. for (int j = stop; j < _data.Length; j++, i++) {
  375. _data.SetData(i, _data.GetData(j));
  376. }
  377. for (i = 0; i < stop - start; i++) {
  378. _data.RemoveAt(_data.Length - 1);
  379. }
  380. return;
  381. }
  382. if (step == -1) {
  383. int i = stop + 1;
  384. for (int j = start + 1; j < _data.Length; j++, i++) {
  385. _data.SetData(i, _data.GetData(j));
  386. }
  387. for (i = 0; i < stop - start; i++) {
  388. _data.RemoveAt(_data.Length - 1);
  389. }
  390. return;
  391. }
  392. if (step < 0) {
  393. // find "start" we will skip in the 1,2,3,... order
  394. int i = start;
  395. while (i > stop) {
  396. i += step;
  397. }
  398. i -= step;
  399. // swap start/stop, make step positive
  400. stop = start + 1;
  401. start = i;
  402. step = -step;
  403. }
  404. int curr, skip, move;
  405. // skip: the next position we should skip
  406. // curr: the next position we should fill in data
  407. // move: the next position we will check
  408. curr = skip = move = start;
  409. while (curr < stop && move < stop) {
  410. if (move != skip) {
  411. _data.SetData(curr++, _data.GetData(move));
  412. } else
  413. skip += step;
  414. move++;
  415. }
  416. while (stop < _data.Length) {
  417. _data.SetData(curr++, _data.GetData(stop++));
  418. }
  419. while (_data.Length > curr) {
  420. _data.RemoveAt(_data.Length - 1);
  421. }
  422. }
  423. public object this[Slice index] {
  424. get {
  425. if (index == null) throw PythonOps.TypeError("expected Slice, got None");
  426. int start, stop, step;
  427. index.indices(_data.Length, out start, out stop, out step);
  428. array pa = new array(new string(_typeCode, 1), Missing.Value);
  429. if (step < 0) {
  430. for (int i = start; i > stop; i += step) {
  431. pa._data.Append(_data.GetData(i));
  432. }
  433. } else {
  434. for (int i = start; i < stop; i += step) {
  435. pa._data.Append(_data.GetData(i));
  436. }
  437. }
  438. return pa;
  439. }
  440. set {
  441. if (index == null) throw PythonOps.TypeError("expected Slice, got None");
  442. CheckSliceAssignType(value);
  443. if (index.step != null) {
  444. if (Object.ReferenceEquals(value, this)) value = this.tolist();
  445. index.DoSliceAssign(SliceAssign, _data.Length, value);
  446. } else {
  447. int start, stop, step;
  448. index.indices(_data.Length, out start, out stop, out step);
  449. if (stop < start) {
  450. stop = start;
  451. }
  452. SliceNoStep(value, start, stop);
  453. }
  454. }
  455. }
  456. private void CheckSliceAssignType(object value) {
  457. array pa = value as array;
  458. if (pa == null) {
  459. throw PythonOps.TypeError("can only assign array (not \"{0}\") to array slice", PythonTypeOps.GetName(value));
  460. } else if (pa != null && pa._typeCode != _typeCode) {
  461. throw PythonOps.TypeError("bad argument type for built-in operation");
  462. }
  463. }
  464. private void SliceNoStep(object value, int start, int stop) {
  465. // replace between start & stop w/ values
  466. IEnumerator ie = PythonOps.GetEnumerator(value);
  467. ArrayData newData = CreateData(_typeCode);
  468. for (int i = 0; i < start; i++) {
  469. newData.Append(_data.GetData(i));
  470. }
  471. while (ie.MoveNext()) {
  472. newData.Append(ie.Current);
  473. }
  474. for (int i = Math.Max(stop, start); i < _data.Length; i++) {
  475. newData.Append(_data.GetData(i));
  476. }
  477. _data = newData;
  478. }
  479. public object __getslice__(object start, object stop) {
  480. return this[new Slice(start, stop)];
  481. }
  482. public void __setslice__(int start, int stop, object value) {
  483. CheckSliceAssignType(value);
  484. Slice.FixSliceArguments(_data.Length, ref start, ref stop);
  485. SliceNoStep(value, start, stop);
  486. }
  487. public void __delslice__(object start, object stop) {
  488. __delitem__(new Slice(start, stop));
  489. }
  490. public PythonTuple __reduce__() {
  491. return PythonOps.MakeTuple(
  492. DynamicHelpers.GetPythonType(this),
  493. PythonOps.MakeTuple(
  494. typecode,
  495. tolist()
  496. ),
  497. null
  498. );
  499. }
  500. public array __copy__() {
  501. return new array(typecode, this);
  502. }
  503. public array __deepcopy__(array arg) {
  504. // we only have simple data so this is the same as a copy
  505. return arg.__copy__();
  506. }
  507. public PythonTuple __reduce_ex__(int version) {
  508. return __reduce__();
  509. }
  510. public PythonTuple __reduce_ex__() {
  511. return __reduce__();
  512. }
  513. private void SliceAssign(int index, object value) {
  514. _data.SetData(index, value);
  515. }
  516. public void tofile(PythonFile f) {
  517. f.write(tostring());
  518. }
  519. public List tolist() {
  520. List res = new List();
  521. for (int i = 0; i < _data.Length; i++) {
  522. res.AddNoLock(this[i]);
  523. }
  524. return res;
  525. }
  526. public string tostring() {
  527. Stream s = ToStream();
  528. byte[] bytes = new byte[s.Length];
  529. s.Read(bytes, 0, (int)s.Length);
  530. StringBuilder res = new StringBuilder();
  531. for (int i = 0; i < bytes.Length; i++) {
  532. res.Append((char)bytes[i]);
  533. }
  534. return res.ToString();
  535. }
  536. public string tounicode(CodeContext/*!*/ context) {
  537. if (_typeCode != 'u') throw PythonOps.ValueError("only 'u' arrays can be converted to unicode");
  538. return new string(((ArrayData<char>)_data).Data, 0, _data.Length);
  539. }
  540. [Python3Warning("array.write() not supported in 3.x; use array.tofile()")]
  541. public void write(PythonFile f) {
  542. tofile(f);
  543. }
  544. public string/*!*/ typecode {
  545. get { return ScriptingRuntimeHelpers.CharToString(_typeCode); }
  546. }
  547. private abstract class ArrayData {
  548. public abstract void SetData(int index, object value);
  549. public abstract object GetData(int index);
  550. public abstract void Append(object value);
  551. public abstract int Count(object value);
  552. public abstract bool CanStore(object value);
  553. public abstract Type StorageType { get; }
  554. public abstract int Index(object value);
  555. public abstract void Insert(int index, object value);
  556. public abstract void Remove(object value);
  557. public abstract void RemoveAt(int index);
  558. public abstract int Length { get; set; }
  559. public abstract void Swap(int x, int y);
  560. public abstract void Clear();
  561. public abstract IntPtr GetAddress();
  562. public abstract ArrayData Multiply(int count);
  563. }
  564. internal MemoryStream ToStream() {
  565. MemoryStream ms = new MemoryStream();
  566. ToStream(ms);
  567. ms.Seek(0, SeekOrigin.Begin);
  568. return ms;
  569. }
  570. internal void ToStream(Stream ms) {
  571. BinaryWriter bw = new BinaryWriter(ms, Encoding.Unicode);
  572. for (int i = 0; i < _data.Length; i++) {
  573. switch (_typeCode) {
  574. case 'c': bw.Write((byte)(char)_data.GetData(i)); break;
  575. case 'b': bw.Write((sbyte)_data.GetData(i)); break;
  576. case 'B': bw.Write((byte)_data.GetData(i)); break;
  577. case 'u': bw.Write((char)_data.GetData(i)); break;
  578. case 'h': bw.Write((short)_data.GetData(i)); break;
  579. case 'H': bw.Write((ushort)_data.GetData(i)); break;
  580. case 'l':
  581. case 'i': bw.Write((int)_data.GetData(i)); break;
  582. case 'L':
  583. case 'I': bw.Write((uint)_data.GetData(i)); break;
  584. case 'f': bw.Write((float)_data.GetData(i)); break;
  585. case 'd': bw.Write((double)_data.GetData(i)); break;
  586. }
  587. }
  588. }
  589. internal byte[] ToByteArray() {
  590. return ToStream().ToArray();
  591. }
  592. internal void Clear() {
  593. _data = CreateData(_typeCode);
  594. }
  595. internal void FromStream(Stream ms) {
  596. BinaryReader br = new BinaryReader(ms);
  597. for (int i = 0; i < ms.Length / itemsize; i++) {
  598. object value;
  599. switch (_typeCode) {
  600. case 'c': value = (char)br.ReadByte(); break;
  601. case 'b': value = (sbyte)br.ReadByte(); break;
  602. case 'B': value = br.ReadByte(); break;
  603. case 'u': value = ReadBinaryChar(br); break;
  604. case 'h': value = br.ReadInt16(); break;
  605. case 'H': value = br.ReadUInt16(); break;
  606. case 'i': value = br.ReadInt32(); break;
  607. case 'I': value = br.ReadUInt32(); break;
  608. case 'l': value = br.ReadInt32(); break;
  609. case 'L': value = br.ReadUInt32(); break;
  610. case 'f': value = br.ReadSingle(); break;
  611. case 'd': value = br.ReadDouble(); break;
  612. default: throw new InvalidOperationException(); // should never happen
  613. }
  614. _data.Append(value);
  615. }
  616. }
  617. // a version of FromStream that overwrites starting at 'index'
  618. internal void FromStream(Stream ms, int index) {
  619. BinaryReader br = new BinaryReader(ms);
  620. for (int i = index; i < ms.Length / itemsize + index; i++) {
  621. object value;
  622. switch (_typeCode) {
  623. case 'c': value = (char)br.ReadByte(); break;
  624. case 'b': value = (sbyte)br.ReadByte(); break;
  625. case 'B': value = br.ReadByte(); break;
  626. case 'u': value = ReadBinaryChar(br); break;
  627. case 'h': value = br.ReadInt16(); break;
  628. case 'H': value = br.ReadUInt16(); break;
  629. case 'i': value = br.ReadInt32(); break;
  630. case 'I': value = br.ReadUInt32(); break;
  631. case 'l': value = br.ReadInt32(); break;
  632. case 'L': value = br.ReadUInt32(); break;
  633. case 'f': value = br.ReadSingle(); break;
  634. case 'd': value = br.ReadDouble(); break;
  635. default: throw new InvalidOperationException(); // should never happen
  636. }
  637. _data.SetData(i, value);
  638. }
  639. }
  640. // a version of FromStream that overwrites up to 'nbytes' bytes, starting at 'index'
  641. // Returns the number of bytes written.
  642. internal long FromStream(Stream ms, int index, int nbytes) {
  643. BinaryReader br = new BinaryReader(ms);
  644. if (nbytes <= 0) {
  645. return 0;
  646. }
  647. int len = Math.Min((int)(ms.Length - ms.Position), nbytes);
  648. for (int i = index; i < len / itemsize + index; i++) {
  649. object value;
  650. switch (_typeCode) {
  651. case 'c': value = (char)br.ReadByte(); break;
  652. case 'b': value = (sbyte)br.ReadByte(); break;
  653. case 'B': value = br.ReadByte(); break;
  654. case 'u':
  655. value = ReadBinaryChar(br);
  656. break;
  657. case 'h': value = br.ReadInt16(); break;
  658. case 'H': value = br.ReadUInt16(); break;
  659. case 'i': value = br.ReadInt32(); break;
  660. case 'I': value = br.ReadUInt32(); break;
  661. case 'l': value = br.ReadInt32(); break;
  662. case 'L': value = br.ReadUInt32(); break;
  663. case 'f': value = br.ReadSingle(); break;
  664. case 'd': value = br.ReadDouble(); break;
  665. default: throw new InvalidOperationException(); // should never happen
  666. }
  667. _data.SetData(i, value);
  668. }
  669. if (len % itemsize > 0) {
  670. // we have some extra bytes that we need to do a partial read on.
  671. byte[] curBytes = ToBytes(len / itemsize + index);
  672. for (int i = 0; i < len % itemsize; i++) {
  673. curBytes[i] = br.ReadByte();
  674. }
  675. _data.SetData(len / itemsize + index, FromBytes(curBytes));
  676. }
  677. return len;
  678. }
  679. // br.ReadChar() doesn't read 16-bit chars, it reads 8-bit chars.
  680. private static object ReadBinaryChar(BinaryReader br) {
  681. object value;
  682. byte byteVal = br.ReadByte();
  683. value = (char)((br.ReadByte() << 8) | byteVal);
  684. return value;
  685. }
  686. private byte[] ToBytes(int index) {
  687. switch(_typeCode) {
  688. case 'c': return new[] { (byte)(char)_data.GetData(index) };
  689. case 'b': return new[] { (byte)(sbyte)_data.GetData(index) };
  690. case 'B': return new[] { (byte)_data.GetData(index) };
  691. case 'u': return BitConverter.GetBytes((char)_data.GetData(index));
  692. case 'h': return BitConverter.GetBytes((short)_data.GetData(index));
  693. case 'H': return BitConverter.GetBytes((ushort)_data.GetData(index));
  694. case 'l':
  695. case 'i': return BitConverter.GetBytes((int)_data.GetData(index));
  696. case 'L':
  697. case 'I': return BitConverter.GetBytes((uint)_data.GetData(index));
  698. case 'f': return BitConverter.GetBytes((float)_data.GetData(index));
  699. case 'd': return BitConverter.GetBytes((double)_data.GetData(index));
  700. default:
  701. throw PythonOps.ValueError("Bad type code (expected one of 'c', 'b', 'B', 'u', 'H', 'h', 'i', 'I', 'l', 'L', 'f', 'd')");
  702. }
  703. }
  704. private object FromBytes(byte[] bytes) {
  705. switch (_typeCode) {
  706. case 'c': return (char)bytes[0];
  707. case 'b': return (sbyte)bytes[0];
  708. case 'B': return bytes[0];
  709. case 'u': return BitConverter.ToChar(bytes, 0);
  710. case 'h': return BitConverter.ToInt16(bytes, 0);
  711. case 'H': return BitConverter.ToUInt16(bytes, 0);
  712. case 'l':
  713. case 'i': return BitConverter.ToInt32(bytes, 0);
  714. case 'L':
  715. case 'I': return BitConverter.ToUInt32(bytes, 0);
  716. case 'f': return BitConverter.ToSingle(bytes, 0);
  717. case 'd': return BitConverter.ToDouble(bytes, 0);
  718. default:
  719. throw PythonOps.ValueError("Bad type code (expected one of 'c', 'b', 'B', 'u', 'H', 'h', 'i', 'I', 'l', 'L', 'f', 'd')");
  720. }
  721. }
  722. private class ArrayData<T> : ArrayData {
  723. private T[] _data;
  724. private int _count;
  725. private GCHandle? _dataHandle;
  726. public ArrayData() {
  727. GC.SuppressFinalize(this);
  728. _data = new T[8];
  729. }
  730. private ArrayData(int size) {
  731. GC.SuppressFinalize(this);
  732. _data = new T[size];
  733. _count = size;
  734. }
  735. ~ArrayData() {
  736. Debug.Assert(_dataHandle.HasValue);
  737. _dataHandle.Value.Free();
  738. }
  739. public T[] Data {
  740. get {
  741. return _data;
  742. }
  743. set {
  744. _data = value;
  745. }
  746. }
  747. public override object GetData(int index) {
  748. return _data[index];
  749. }
  750. public override void SetData(int index, object value) {
  751. _data[index] = GetValue(value);
  752. }
  753. private static T GetValue(object value) {
  754. if (!(value is T)) {
  755. object newVal;
  756. if (!Converter.TryConvert(value, typeof(T), out newVal)) {
  757. if (value != null && typeof(T).GetTypeInfo().IsPrimitive && typeof(T) != typeof(char))
  758. throw PythonOps.OverflowError("couldn't convert {1} to {0}",
  759. DynamicHelpers.GetPythonTypeFromType(typeof(T)).Name,
  760. DynamicHelpers.GetPythonType(value).Name);
  761. throw PythonOps.TypeError("expected {0}, got {1}",
  762. DynamicHelpers.GetPythonTypeFromType(typeof(T)).Name,
  763. DynamicHelpers.GetPythonType(value).Name);
  764. }
  765. value = newVal;
  766. }
  767. return (T)value;
  768. }
  769. public override void Append(object value) {
  770. EnsureSize(_count + 1);
  771. _data[_count++] = GetValue(value);
  772. }
  773. public void EnsureSize(int size) {
  774. if (_data.Length < size) {
  775. Array.Resize(ref _data, _data.Length * 2);
  776. if (_dataHandle != null) {
  777. _dataHandle.Value.Free();
  778. _dataHandle = null;
  779. GC.SuppressFinalize(this);
  780. }
  781. }
  782. }
  783. public override int Count(object value) {
  784. T other = GetValue(value);
  785. int count = 0;
  786. for (int i = 0; i < _count; i++) {
  787. if (_data[i].Equals(other)) {
  788. count++;
  789. }
  790. }
  791. return count;
  792. }
  793. public override void Insert(int index, object value) {
  794. EnsureSize(_count + 1);
  795. if (index < _count) {
  796. Array.Copy(_data, index, _data, index + 1, _count - index);
  797. }
  798. _data[index] = GetValue(value);
  799. _count++;
  800. }
  801. public override int Index(object value) {
  802. T other = GetValue(value);
  803. for (int i = 0; i < _count; i++) {
  804. if (_data[i].Equals(other)) return i;
  805. }
  806. return -1;
  807. }
  808. public override void Remove(object value) {
  809. T other = GetValue(value);
  810. for (int i = 0; i < _count; i++) {
  811. if (_data[i].Equals(other)) {
  812. RemoveAt(i);
  813. return;
  814. }
  815. }
  816. throw PythonOps.ValueError("couldn't find value to remove");
  817. }
  818. public override void RemoveAt(int index) {
  819. _count--;
  820. if (index < _count) {
  821. Array.Copy(_data, index + 1, _data, index, _count - index);
  822. }
  823. }
  824. public override void Swap(int x, int y) {
  825. T temp = _data[x];
  826. _data[x] = _data[y];
  827. _data[y] = temp;
  828. }
  829. public override int Length {
  830. get {
  831. return _count;
  832. }
  833. set {
  834. _count = value;
  835. }
  836. }
  837. public override void Clear() {
  838. _count = 0;
  839. }
  840. public override bool CanStore(object value) {
  841. object tmp;
  842. if (!(value is T) && !Converter.TryConvert(value, typeof(T), out tmp))
  843. return false;
  844. return true;
  845. }
  846. public override Type StorageType {
  847. get { return typeof(T); }
  848. }
  849. public override IntPtr GetAddress() {
  850. // slightly evil to pin our data array but it's only used in rare
  851. // interop cases. If this becomes a problem we can move the allocation
  852. // onto the unmanaged heap if we have full trust via a different subclass
  853. // of ArrayData.
  854. if (!_dataHandle.HasValue) {
  855. _dataHandle = GCHandle.Alloc(_data, GCHandleType.Pinned);
  856. GC.ReRegisterForFinalize(this);
  857. }
  858. return _dataHandle.Value.AddrOfPinnedObject();
  859. }
  860. public override ArrayData Multiply(int count) {
  861. var res = new ArrayData<T>(count * _count);
  862. if (count != 0) {
  863. Array.Copy(_data, res._data, _count);
  864. int newCount = count * _count;
  865. int block = _count;
  866. int pos = _count;
  867. while (pos < newCount) {
  868. Array.Copy(res._data, 0, res._data, pos, Math.Min(block, newCount - pos));
  869. pos += block;
  870. block *= 2;
  871. }
  872. }
  873. return res;
  874. }
  875. }
  876. #region IValueEquality Members
  877. #if CLR2
  878. int IValueEquality.GetValueHashCode() {
  879. throw PythonOps.TypeError("unhashable type");
  880. }
  881. bool IValueEquality.ValueEquals(object other) {
  882. array pa = other as array;
  883. if (pa == null) return false;
  884. if (_data.Length != pa._data.Length) return false;
  885. for (int i = 0; i < _data.Length; i++) {
  886. if (!_data.GetData(i).Equals(pa._data.GetData(i))) {
  887. return false;
  888. }
  889. }
  890. return true;
  891. }
  892. #endif
  893. #endregion
  894. #region IStructuralEquatable Members
  895. public const object __hash__ = null;
  896. int IStructuralEquatable.GetHashCode(IEqualityComparer comparer) {
  897. IStructuralEquatable dataTuple;
  898. switch(_typeCode) {
  899. case 'c': dataTuple = PythonTuple.MakeTuple(((ArrayData<char>)_data).Data); break;
  900. case 'b': dataTuple = PythonTuple.MakeTuple(((ArrayData<sbyte>)_data).Data); break;
  901. case 'B': dataTuple = PythonTuple.MakeTuple(((ArrayData<byte>)_data).Data); break;
  902. case 'u': dataTuple = PythonTuple.MakeTuple(((ArrayData<char>)_data).Data); break;
  903. case 'h': dataTuple = PythonTuple.MakeTuple(((ArrayData<short>)_data).Data); break;
  904. case 'H': dataTuple = PythonTuple.MakeTuple(((ArrayData<ushort>)_data).Data); break;
  905. case 'l':
  906. case 'i': dataTuple = PythonTuple.MakeTuple(((ArrayData<int>)_data).Data); break;
  907. case 'L':
  908. case 'I': dataTuple = PythonTuple.MakeTuple(((ArrayData<uint>)_data).Data); break;
  909. case 'f': dataTuple = PythonTuple.MakeTuple(((ArrayData<float>)_data).Data); break;
  910. case 'd': dataTuple = PythonTuple.MakeTuple(((ArrayData<double>)_data).Data); break;
  911. default:
  912. throw PythonOps.ValueError("Bad type code (expected one of 'c', 'b', 'B', 'u', 'H', 'h', 'i', 'I', 'l', 'L', 'f', 'd')");
  913. }
  914. return dataTuple.GetHashCode(comparer);
  915. }
  916. bool IStructuralEquatable.Equals(object other, IEqualityComparer comparer) {
  917. array pa = other as array;
  918. if (pa == null) return false;
  919. if (_data.Length != pa._data.Length) return false;
  920. for (int i = 0; i < _data.Length; i++) {
  921. if (!comparer.Equals(_data.GetData(i), pa._data.GetData(i))) {
  922. return false;
  923. }
  924. }
  925. return true;
  926. }
  927. #endregion
  928. #region IEnumerable Members
  929. IEnumerator IEnumerable.GetEnumerator() {
  930. for (int i = 0; i < _data.Length; i++) {
  931. yield return _data.GetData(i);
  932. }
  933. }
  934. #endregion
  935. #region ICodeFormattable Members
  936. public virtual string/*!*/ __repr__(CodeContext/*!*/ context) {
  937. string res = "array('" + typecode.ToString() + "'";
  938. if (_data.Length == 0) {
  939. return res + ")";
  940. }
  941. StringBuilder sb = new StringBuilder(res);
  942. if (_typeCode == 'c' || _typeCode == 'u') {
  943. char quote = '\'';
  944. string s = new string(((ArrayData<char>)_data).Data, 0, _data.Length);
  945. if (s.IndexOf('\'') != -1 && s.IndexOf('\"') == -1) {
  946. quote = '\"';
  947. }
  948. if (_typeCode == 'u') {
  949. sb.Append(", u");
  950. } else {
  951. sb.Append(", ");
  952. }
  953. sb.Append(quote);
  954. bool isUnicode = false;
  955. sb.Append(StringOps.ReprEncode(s, quote, ref isUnicode));
  956. sb.Append(quote);
  957. sb.Append(")");
  958. } else {
  959. sb.Append(", [");
  960. for (int i = 0; i < _data.Length; i++) {
  961. if (i > 0) {
  962. sb.Append(", ");
  963. }
  964. sb.Append(PythonOps.Repr(context, this[i]));
  965. }
  966. sb.Append("])");
  967. }
  968. return sb.ToString();
  969. }
  970. #endregion
  971. #region IWeakReferenceable Members
  972. WeakRefTracker IWeakReferenceable.GetWeakRef() {
  973. return _tracker;
  974. }
  975. bool IWeakReferenceable.SetWeakRef(WeakRefTracker value) {
  976. _tracker = value;
  977. return true;
  978. }
  979. void IWeakReferenceable.SetFinalizer(WeakRefTracker value) {
  980. _tracker = value;
  981. }
  982. #endregion
  983. #region IPythonContainer Members
  984. public int __len__() {
  985. return _data.Length;
  986. }
  987. public bool __contains__(object value) {
  988. return _data.Index(value) != -1;
  989. }
  990. #endregion
  991. #region IRichComparable Members
  992. private bool TryCompare(object other, out int res) {
  993. array pa = other as array;
  994. if (pa == null || pa.typecode != typecode) {
  995. res = 0;
  996. return false;
  997. }
  998. if (pa._data.Length != _data.Length) {
  999. res = _data.Length - pa._data.Length;
  1000. } else {
  1001. res = 0;
  1002. for (int i = 0; i < pa._data.Length && res == 0; i++) {
  1003. res = PythonOps.Compare(_data.GetData(i), pa._data.GetData(i));
  1004. }
  1005. }
  1006. return true;
  1007. }
  1008. [return: MaybeNotImplemented]
  1009. public static object operator >(array self, object other) {
  1010. int res;
  1011. if (!self.TryCompare(other, out res)) {
  1012. return NotImplementedType.Value;
  1013. }
  1014. return ScriptingRuntimeHelpers.BooleanToObject(res > 0);
  1015. }
  1016. [return: MaybeNotImplemented]
  1017. public static object operator <(array self, object other) {
  1018. int res;
  1019. if (!self.TryCompare(other, out res)) {
  1020. return NotImplementedType.Value;
  1021. }
  1022. return ScriptingRuntimeHelpers.BooleanToObject(res < 0);
  1023. }
  1024. [return: MaybeNotImplemented]
  1025. public static object operator >=(array self, object other) {
  1026. int res;
  1027. if (!self.TryCompare(other, out res)) {
  1028. return NotImplementedType.Value;
  1029. }
  1030. return ScriptingRuntimeHelpers.BooleanToObject(res >= 0);
  1031. }
  1032. [return: MaybeNotImplemented]
  1033. public static object operator <=(array self, object other) {
  1034. int res;
  1035. if (!self.TryCompare(other, out res)) {
  1036. return NotImplementedType.Value;
  1037. }
  1038. return ScriptingRuntimeHelpers.BooleanToObject(res <= 0);
  1039. }
  1040. #endregion
  1041. #region ICollection Members
  1042. void ICollection.CopyTo(Array array, int index) {
  1043. throw new NotImplementedException();
  1044. }
  1045. int ICollection.Count {
  1046. get { return __len__(); }
  1047. }
  1048. bool ICollection.IsSynchronized {
  1049. get { return false; }
  1050. }
  1051. object ICollection.SyncRoot {
  1052. get { return this; }
  1053. }
  1054. #endregion
  1055. #region IList<object> Members
  1056. int IList<object>.IndexOf(object item) {
  1057. return _data.Index(item);
  1058. }
  1059. void IList<object>.Insert(int index, object item) {
  1060. insert(index, item);
  1061. }
  1062. void IList<object>.RemoveAt(int index) {
  1063. __delitem__(index);
  1064. }
  1065. #endregion
  1066. #region ICollection<object> Members
  1067. void ICollection<object>.Add(object item) {
  1068. append(item);
  1069. }
  1070. void ICollection<object>.Clear() {
  1071. __delitem__(new Slice(null, null));
  1072. }
  1073. bool ICollection<object>.Contains(object

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