PageRenderTime 56ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/Backend/Runtime/List.cs

https://bitbucket.org/AdamMil/boaold
C# | 342 lines | 269 code | 52 blank | 21 comment | 90 complexity | b4bb6621ac0c36882b069bf2e688c79a MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. Boa is the reference implementation for a language similar to Python,
  3. also called Boa. This implementation is both interpreted and compiled,
  4. targeting the Microsoft .NET Framework.
  5. http://www.adammil.net/
  6. Copyright (C) 2004-2005 Adam Milazzo
  7. This program is free software; you can redistribute it and/or
  8. modify it under the terms of the GNU General Public License
  9. as published by the Free Software Foundation; either version 2
  10. of the License, or (at your option) any later version.
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. GNU General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  18. */
  19. using System;
  20. using System.Collections;
  21. // TODO: don't allow __repr__ to go into an infinite loop with circular references
  22. namespace Boa.Runtime
  23. {
  24. [BoaType("list")]
  25. public class List : IMutableSequence, IList, IComparable, ICloneable, IRepresentable
  26. { public List() { items = new object[16]; }
  27. public List(int capacity) { items = new object[Math.Max(capacity, 4)]; }
  28. public List(ICollection c) : this(c.Count) { c.CopyTo(items, 0); size=c.Count; }
  29. public List(IEnumerator e) : this() { while(e.MoveNext()) append(e.Current); }
  30. public List(object o) : this(Ops.GetEnumerator(o)) { }
  31. internal List(object[] arr, int length) { items=arr; size=length; }
  32. public void append(object item)
  33. { ResizeTo(size+1);
  34. items[size++] = item;
  35. }
  36. public int count(object item)
  37. { int num=0;
  38. for(int i=0; i<size; i++) if(items[i].Equals(item)) num++;
  39. return num;
  40. }
  41. public void extend(object seq)
  42. { List list = this;
  43. if(!TryAppend(seq, ref list))
  44. { IEnumerator e = Ops.GetEnumerator(seq);
  45. while(e.MoveNext()) append(e.Current);
  46. }
  47. }
  48. public override bool Equals(object o) { return CompareTo(o)==0; }
  49. public override int GetHashCode() { throw Ops.TypeError("list objects are unhashable"); }
  50. public int index(object item) { return IndexOrError(IndexOf(item, 0, size)); }
  51. public int index(object item, int start)
  52. { start = Ops.FixIndex(start, size);
  53. return IndexOrError(IndexOf(item, start, size-start));
  54. }
  55. public int index(object item, int start, int end)
  56. { start = Ops.FixIndex(start, size);
  57. end = Ops.FixIndex(end, size);
  58. if(start>end) { int t=end; end=start; start=t; }
  59. return IndexOrError(IndexOf(item, start, end-start));
  60. }
  61. public void insert(int index, object o) { Insert(index==size ? index : Ops.FixIndex(index, size), o); }
  62. public object pop()
  63. { if(size==0) throw Ops.ValueError("pop off of empty list");
  64. return items[--size];
  65. }
  66. public void remove(object item) { RemoveAt(index(item)); }
  67. public void RemoveRange(int start, int count)
  68. { if(start<0 || start+count>size) throw Ops.ValueError("RemoveRange(): indices out of range");
  69. size -= count;
  70. for(; start<size; start++) items[start] = items[start+count];
  71. for(int i=0; i<count; i++) items[size+i] = null;
  72. }
  73. public void reverse() { Array.Reverse(items, 0, size); }
  74. public void sort() { Array.Sort(items, 0, size, Ops.DefaultComparer); }
  75. public void sort(object cmpfunc) { Array.Sort(items, 0, size, new FunctionComparer(cmpfunc)); }
  76. public List sorted()
  77. { List ret = new List(this);
  78. ret.sort();
  79. return ret;
  80. }
  81. public List sorted(object cmpfunc)
  82. { List ret = new List(this);
  83. ret.sort(cmpfunc);
  84. return ret;
  85. }
  86. public Tuple ToTuple()
  87. { object[] ti = new object[size];
  88. items.CopyTo(ti, 0);
  89. return new Tuple(ti);
  90. }
  91. #region IMutableSequence Members
  92. public object __add__(object o)
  93. { List list=null;
  94. if(!TryAppend(o, ref list))
  95. throw Ops.TypeError("can not concatenate list to ('{0}')", Ops.GetDynamicType(o).__name__);
  96. return list;
  97. }
  98. public bool __contains__(object value) { return IndexOf(value, 0, size) != -1; }
  99. public void __delitem__(int index) { RemoveAt(Ops.FixIndex(index, size)); }
  100. public void __delitem__(Slice slice)
  101. { Tuple tup = slice.indices(size);
  102. int start=(int)tup.items[0], stop=(int)tup.items[1], step=(int)tup.items[2];
  103. if(step<0 && start<=stop || step>0 && start>=stop) return;
  104. if(step==1) RemoveRange(start, stop-start);
  105. else if(step==-1) RemoveRange(stop+1, start-stop);
  106. else
  107. { int off=1;
  108. for(int i=start,next=start+step; i<size; i++)
  109. { if(i+off==next) { if((next+=step)>=stop) next=0; else off++; }
  110. items[i] = items[i+off];
  111. }
  112. size -= off;
  113. }
  114. }
  115. public object __getitem__(int index) { return items[Ops.FixIndex(index, size)]; }
  116. public object __getitem__(Slice slice) { return Ops.SequenceSlice(this, slice); }
  117. public int __len__() { return size; }
  118. public void __setitem__(int index, object value) { items[Ops.FixIndex(index, size)] = value; }
  119. public void __setitem__(Slice slice, object value)
  120. { Tuple tup = slice.indices(size);
  121. int start=(int)tup.items[0], stop=(int)tup.items[1], step=(int)tup.items[2];
  122. if(step<0 && start<=stop || step>0 && start>=stop) return;
  123. int sign=Math.Sign(step), slen=(stop-start+step-sign)/step;
  124. ISequence seq = value as ISequence;
  125. if(seq==null && value is string) seq = new StringOps.SequenceWrapper((string)value);
  126. int len = seq==null ? Ops.ToInt(Ops.Invoke(value, "__len__")) : seq.__len__();
  127. if(step==1 || step==-1)
  128. { int diff = Math.Abs(len-slen);
  129. if(step==1)
  130. { if(len<slen) RemoveRange(start+len, diff);
  131. else if(len>slen) Insert(start+slen, diff);
  132. }
  133. else if(len>slen) { Insert(stop+1, diff); start += diff; }
  134. else if(len<slen) { RemoveRange(stop+1, diff); start -= diff; }
  135. }
  136. else if(len!=slen)
  137. throw Ops.ValueError("can't assign sequence of size {0} to extended slice of size {1}", len, slen);
  138. if(seq!=null)
  139. { if(step==1) for(int i=0; i<len; i++) items[i+start] = seq.__getitem__(i);
  140. else if(step==-1) for(int i=0; i<len; i++) items[start-i] = seq.__getitem__(i);
  141. else if(step>0) for(int i=0; start<stop; i++,start+=step) items[start] = seq.__getitem__(i);
  142. else for(int i=0; start>stop; i++,start+=step) items[start] = seq.__getitem__(i);
  143. }
  144. else
  145. { object getitem = Ops.GetAttr(value, "__getitem__");
  146. if(step==1) for(int i=0; i<len; i++) items[i+start] = Ops.Call(getitem, i);
  147. else if(step==-1) for(int i=0; i<len; i++) items[start-i] = Ops.Call(getitem, i);
  148. else if(step>0) for(int i=0; start<stop; i++,start+=step) items[start] = Ops.Call(getitem, i);
  149. else for(int i=0; start>stop; i++,start+=step) items[start] = Ops.Call(getitem, i);
  150. }
  151. }
  152. #endregion
  153. #region IList Members
  154. public bool IsReadOnly { get { return false; } }
  155. public object this[int index]
  156. { get
  157. { if(index<0 || index>=size) throw new IndexOutOfRangeException();
  158. return items[index];
  159. }
  160. set
  161. { if(index<0 || index>=size) throw new IndexOutOfRangeException();
  162. items[index] = value;
  163. }
  164. }
  165. public void RemoveAt(int index)
  166. { if(index<0 || index>=size) throw new IndexOutOfRangeException();
  167. size--;
  168. for(; index<size; index++) items[index] = items[index+1];
  169. items[size] = null;
  170. }
  171. public void Insert(int index, object value)
  172. { if(index<0 || index>size) throw new IndexOutOfRangeException();
  173. ResizeTo(size+1);
  174. for(int i=size++; i>index; i--) items[i] = items[i-1];
  175. items[index] = value;
  176. }
  177. public void Remove(object value)
  178. { int index = IndexOf(value);
  179. if(index!=-1) RemoveAt(index);
  180. }
  181. public bool Contains(object value) { return __contains__(value); }
  182. public void Clear() { size=0; }
  183. public int IndexOf(object value) { return IndexOf(value, 0, size); }
  184. public int IndexOf(object value, int start, int length)
  185. { int end = start+length;
  186. if(start<0 || end>size) throw new ArgumentOutOfRangeException();
  187. for(; start<end; start++) if(Ops.Compare(items[start], value)==0) return start;
  188. return -1;
  189. }
  190. public int Add(object value) { append(value); return size-1; }
  191. public bool IsFixedSize { get { return false; } }
  192. #endregion
  193. #region ICollection Members
  194. public bool IsSynchronized { get { return false; } }
  195. public int Count { get { return size; } }
  196. public void CopyTo(Array array, int index) { Array.Copy(items, 0, array, index, size); }
  197. public object SyncRoot { get { return this; } }
  198. #endregion
  199. #region IEnumerable Members
  200. public IEnumerator GetEnumerator() { return new ListEnumerator(this); }
  201. class ListEnumerator : IEnumerator
  202. { public ListEnumerator(List list) { this.list=list; index=-1; }
  203. public void Reset() { index=-1; }
  204. public object Current
  205. { get
  206. { if(index<0 || index>=list.size) throw new InvalidOperationException();
  207. return list.items[index];
  208. }
  209. }
  210. public bool MoveNext()
  211. { if(index>=list.size-1) return false;
  212. index++;
  213. return true;
  214. }
  215. List list;
  216. int index;
  217. }
  218. #endregion
  219. #region IComparable Members
  220. public int CompareTo(object o)
  221. { List list = o as List;
  222. return list==null ? -1 : ArrayOps.Compare(items, size, list.items, list.size); // FIXME: compare by type name
  223. }
  224. #endregion
  225. #region ICloneable Members
  226. public object Clone() { return new List(this); }
  227. #endregion
  228. #region IRepresentable Members
  229. public string __repr__()
  230. { System.Text.StringBuilder sb = new System.Text.StringBuilder();
  231. sb.Append('[');
  232. for(int i=0; i<size; i++)
  233. { if(i>0) sb.Append(", ");
  234. sb.Append(Ops.Repr(items[i]));
  235. }
  236. sb.Append(']');
  237. return sb.ToString();
  238. }
  239. #endregion
  240. public override string ToString() { return __repr__(); }
  241. class FunctionComparer : IComparer
  242. { public FunctionComparer(object func) { this.func=func; }
  243. public int Compare(object x, object y) { return Ops.ToInt(Ops.Call(func, x, y)); }
  244. object func;
  245. }
  246. int IndexOrError(int index)
  247. { if(index<0) throw Ops.ValueError("item not in list");
  248. return index;
  249. }
  250. void Insert(int start, int count)
  251. { ResizeTo(size+count);
  252. for(int i=size-1; i>=start; i--) items[i+count] = items[i];
  253. size += count;
  254. }
  255. void ResizeTo(int capacity)
  256. { if(capacity>items.Length)
  257. { int len = Math.Max(items.Length, 4);
  258. while(len<capacity) len*=2;
  259. object[] arr = new object[len];
  260. Array.Copy(items, arr, size);
  261. items = arr;
  262. }
  263. }
  264. bool TryAppend(object o, ref List list)
  265. { ICollection col = o as ICollection;
  266. if(col!=null)
  267. { if(list==null)
  268. { list = new List(size+col.Count);
  269. Array.Copy(items, list.items, size);
  270. }
  271. else list.ResizeTo(size+col.Count);
  272. col.CopyTo(list.items, size);
  273. list.size = size+col.Count;
  274. }
  275. else
  276. { IEnumerator e;
  277. if(Ops.GetEnumerator(o, out e))
  278. { if(list==null) list = new List(this);
  279. while(e.MoveNext()) list.append(e.Current);
  280. }
  281. else return false;
  282. }
  283. return true;
  284. }
  285. object[] items;
  286. int size;
  287. }
  288. } // namespace Boa.Runtime