PageRenderTime 52ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/ClojureCLR/Clojure/Clojure/Lib/PersistentList.cs

https://github.com/dsebban/clojure-contrib
C# | 523 lines | 283 code | 91 blank | 149 comment | 23 complexity | 1b5bb802e037a4f0c69ce07b5efbae7f MD5 | raw file
  1. /**
  2. * Copyright (c) David Miller. All rights reserved.
  3. * The use and distribution terms for this software are covered by the
  4. * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
  5. * which can be found in the file epl-v10.html at the root of this distribution.
  6. * By using this software in any fashion, you are agreeing to be bound by
  7. * the terms of this license.
  8. * You must not remove this notice, or any other, from this software.
  9. **/
  10. using System;
  11. using System.Collections.Generic;
  12. using System.Collections;
  13. using System.Linq;
  14. using System.Text;
  15. namespace clojure.lang
  16. {
  17. /// <summary>
  18. /// Represents a persistent list.
  19. /// </summary>
  20. public class PersistentList: ASeq, IPersistentList, IReduce, IList, Counted
  21. {
  22. #region Data
  23. /// <summary>
  24. /// The first item in the list.
  25. /// </summary>
  26. private readonly object _first;
  27. /// <summary>
  28. /// The rest of the list.
  29. /// </summary>
  30. private readonly IPersistentList _rest;
  31. /// <summary>
  32. /// The number of items in the list.
  33. /// </summary>
  34. private readonly int _count;
  35. /// <summary>
  36. /// An empty <see cref="IPersistentList">IPersistentList</see>.
  37. /// </summary>
  38. public static readonly EmptyList EMPTY = new EmptyList(null);
  39. #endregion
  40. #region C-tors
  41. /// <summary>
  42. /// Initializes a list of one member.
  43. /// </summary>
  44. /// <param name="first">The one member.</param>
  45. public PersistentList(object first)
  46. {
  47. this._first = first;
  48. this._rest = null;
  49. this._count = 1;
  50. }
  51. /// <summary>
  52. /// Create a list initialized from a given IList.
  53. /// </summary>
  54. /// <param name="init">The list to initialize from.</param>
  55. /// <returns>A list.</returns>
  56. public static IPersistentList create(IList init)
  57. {
  58. IPersistentList ret = EMPTY;
  59. for (int i = init.Count - 1; i >= 0; --i)
  60. ret = (IPersistentList) ret.cons(init[i]);
  61. return ret;
  62. }
  63. /// <summary>
  64. /// Initialize a list with given metadata, first element and rest of list.
  65. /// </summary>
  66. /// <param name="meta">The metadata to attach.</param>
  67. /// <param name="first">The first element in the list.</param>
  68. /// <param name="rest">The rest of the list.</param>
  69. /// <param name="count">The number of elements in the list.</param>
  70. PersistentList(IPersistentMap meta, Object first, IPersistentList rest, int count)
  71. : base(meta)
  72. {
  73. this._first = first;
  74. this._rest = rest;
  75. this._count = count;
  76. }
  77. /// <summary>
  78. /// Provides a function to create a list from a sequence of arguments. (Internal use only.)
  79. /// </summary>
  80. /// <remarks>Internal use only. Used to interface with core.clj.</remarks>
  81. sealed class PLCreator : RestFn
  82. {
  83. /// <summary>
  84. /// Create the function with requiredArity=0.
  85. /// </summary>
  86. public PLCreator()
  87. : base(0)
  88. {
  89. }
  90. /// <summary>
  91. /// The creator method.
  92. /// </summary>
  93. /// <param name="args">A sequence of elements.</param>
  94. /// <returns>A new list.</returns>
  95. protected override object doInvoke(object args)
  96. {
  97. if (args is ArraySeq)
  98. {
  99. object[] argsarray = (object[])((ArraySeq)args).ToArray();
  100. IPersistentList ret = EMPTY;
  101. for (int i = argsarray.Length - 1; i >= 0; i--)
  102. ret = (IPersistentList)ret.cons(argsarray[i]);
  103. return ret;
  104. }
  105. List<object> list = new List<object>();
  106. for (ISeq s = RT.seq(args); s != null; s = s.next())
  107. list.Add(s.first());
  108. return create(list);
  109. }
  110. }
  111. /// <summary>
  112. /// An <see cref="IFn">IFn</see> to create a list from a sequence of items.
  113. /// </summary>
  114. /// <remarks>The name is without our usual leading underscore for compatiblity with core.clj.</remarks>
  115. public static IFn creator = new PLCreator();
  116. #endregion
  117. #region IObj members
  118. public override IObj withMeta(IPersistentMap meta)
  119. {
  120. return meta == _meta
  121. ? this
  122. : new PersistentList(meta, _first, _rest, _count);
  123. }
  124. #endregion
  125. #region ISeq members
  126. /// <summary>
  127. /// Gets the first item.
  128. /// </summary>
  129. /// <returns>The first item.</returns>
  130. public override object first()
  131. {
  132. return _first;
  133. }
  134. /// <summary>
  135. /// Return a seq of the items after the first. Calls <c>seq</c> on its argument. If there are no more items, returns nil."
  136. /// </summary>
  137. /// <returns>A seq of the items after the first, or <c>nil</c> if there are no more items.</returns>
  138. public override ISeq next()
  139. {
  140. if ( _count == 1 )
  141. return null;
  142. return _rest.seq();
  143. }
  144. /// <summary>
  145. /// Adds an item to the beginning of the list.
  146. /// </summary>
  147. /// <param name="o">The item to add.</param>
  148. /// <returns>A new list containing the new item in front of the items already in the sequence.</returns>
  149. public override ISeq cons(Object o)
  150. {
  151. return new PersistentList(meta(), o, this, _count + 1);
  152. }
  153. #endregion
  154. #region IPersistentStack Members
  155. /// <summary>
  156. /// Peek at the top (first) element in the stack.
  157. /// </summary>
  158. /// <returns>The top (first) element.</returns>
  159. public object peek()
  160. {
  161. return _first;
  162. }
  163. /// <summary>
  164. /// Returns a new stack with the top element popped.
  165. /// </summary>
  166. /// <returns>The new stack</returns>
  167. public IPersistentStack pop()
  168. {
  169. return _rest == null
  170. ? (IPersistentList)EMPTY.withMeta(_meta)
  171. : _rest;
  172. }
  173. #endregion
  174. #region IPersistentCollection members
  175. /// <summary>
  176. /// Gets the number of items in the collection.
  177. /// </summary>
  178. /// <returns>The number of items in the collection.</returns>
  179. public override int count()
  180. {
  181. return _count;
  182. }
  183. /// <summary>
  184. /// Gets an empty collection of the same type.
  185. /// </summary>
  186. /// <returns>An emtpy collection.</returns>
  187. public override IPersistentCollection empty()
  188. {
  189. return (IPersistentCollection)EMPTY.withMeta(meta());
  190. }
  191. #endregion
  192. #region IReduce Members
  193. /// <summary>
  194. /// Reduce the collection using a function.
  195. /// </summary>
  196. /// <param name="f">The function to apply.</param>
  197. /// <returns>The reduced value</returns>
  198. public object reduce(IFn f)
  199. {
  200. object ret = first();
  201. for (ISeq s = next(); s != null; s = s.next())
  202. ret = f.invoke(ret, s.first());
  203. return ret;
  204. }
  205. /// <summary>
  206. /// Reduce the collection using a function.
  207. /// </summary>
  208. /// <param name="f">The function to apply.</param>
  209. /// <param name="start">An initial value to get started.</param>
  210. /// <returns>The reduced value</returns>
  211. public object reduce(IFn f, object start)
  212. {
  213. object ret = f.invoke(start, first());
  214. for (ISeq s = next(); s != null; s = s.next())
  215. ret = f.invoke(ret, s.first());
  216. return ret;
  217. }
  218. #endregion
  219. /// <summary>
  220. /// Represents an empty <see cref="IPersistentList">IPersistentList</see>.
  221. /// </summary>
  222. public class EmptyList : Obj, IPersistentList, IList, ISeq, Counted
  223. {
  224. #region C-tors
  225. /// <summary>
  226. /// Initialize an <see cref="EmptyList">PersistentList.EmptyList</see> with given metadata.
  227. /// </summary>
  228. /// <param name="meta">The metadata to attach.</param>
  229. public EmptyList(IPersistentMap meta)
  230. : base(meta)
  231. {
  232. }
  233. /// <summary>
  234. /// Initialize an <see cref="EmptyList">PersistentList.EmptyList</see> with null metadata.
  235. /// </summary>
  236. EmptyList()
  237. {
  238. }
  239. #endregion
  240. #region Object overrides
  241. /// <summary>
  242. /// Return the hash code for the object.
  243. /// </summary>
  244. /// <returns>The hash code</returns>
  245. public override int GetHashCode()
  246. {
  247. return -1;
  248. }
  249. /// <summary>
  250. /// Determines if an object is equal to the current object.
  251. /// </summary>
  252. /// <param name="obj">The object to compare to.</param>
  253. /// <returns><value>true</value> if the object is the same; <value>false</value> otherwise.</returns>
  254. /// <remarks>
  255. /// Equality is value-based. Any empty sequence will do.
  256. /// </remarks>
  257. public override bool Equals(object obj)
  258. {
  259. return (obj is Sequential || obj is IList) && RT.seq(obj) == null;
  260. }
  261. #endregion
  262. #region IObj methods
  263. /// <summary>
  264. /// Create a copy with new metadata.
  265. /// </summary>
  266. /// <param name="meta">The new metadata.</param>
  267. /// <returns>A copy of the object with new metadata attached.</returns>
  268. public override IObj withMeta(IPersistentMap meta)
  269. {
  270. return meta == _meta
  271. ? this
  272. : new EmptyList(meta);
  273. }
  274. #endregion
  275. #region ISeq Members
  276. public object first()
  277. {
  278. return null;
  279. }
  280. public ISeq next()
  281. {
  282. return null;
  283. }
  284. public ISeq more()
  285. {
  286. return this;
  287. }
  288. public ISeq cons(object o)
  289. {
  290. return new PersistentList(meta(), o, null, 1);
  291. }
  292. #endregion
  293. #region IPersistentStack Members
  294. /// <summary>
  295. /// Peek at the top (first) element in the stack.
  296. /// </summary>
  297. /// <returns>The top (first) element. )(Always null.)</returns>
  298. public object peek()
  299. {
  300. return null;
  301. }
  302. /// <summary>
  303. /// Returns a new stack with the top element popped.
  304. /// </summary>
  305. /// <returns>The new stack. Always throws an exception.</returns>
  306. public IPersistentStack pop()
  307. {
  308. throw new InvalidOperationException("Can't pop empty list");
  309. }
  310. #endregion
  311. #region IPersistentCollection Members
  312. /// <summary>
  313. /// Gets the number of items in the collection.
  314. /// </summary>
  315. /// <returns>The number of items in the collection. Always zero.</returns>
  316. public int count()
  317. {
  318. return 0;
  319. }
  320. /// <summary>
  321. /// Gets an ISeq to allow first/rest iteration through the collection.
  322. /// </summary>
  323. /// <returns>An ISeq for iteration. The sequence is empty, so always null.</returns>
  324. public ISeq seq()
  325. {
  326. return null;
  327. }
  328. IPersistentCollection IPersistentCollection.cons(object o)
  329. {
  330. return cons(o);
  331. }
  332. /// <summary>
  333. /// Gets an empty collection of the same type.
  334. /// </summary>
  335. /// <returns>An emtpy collection. Always returns itself.</returns>
  336. public IPersistentCollection empty()
  337. {
  338. return this;
  339. }
  340. /// <summary>
  341. /// Determine if an object is equivalent to this (handles all collections).
  342. /// </summary>
  343. /// <param name="o">The object to compare.</param>
  344. /// <returns><c>true</c> if the object is equivalent; <c>false</c> otherwise.</returns>
  345. public bool equiv(object o)
  346. {
  347. return Equals(o);
  348. }
  349. #endregion
  350. #region ICollection Members
  351. public void CopyTo(Array array, int index)
  352. {
  353. // no-op: no items to copy.
  354. }
  355. public int Count
  356. {
  357. get { return 0; }
  358. }
  359. public bool IsSynchronized
  360. {
  361. get { return true; }
  362. }
  363. public object SyncRoot
  364. {
  365. get { throw new NotImplementedException(); }
  366. }
  367. #endregion
  368. #region IEnumerable Members
  369. public IEnumerator GetEnumerator()
  370. {
  371. yield break;
  372. }
  373. #endregion
  374. #region IList Members
  375. public int Add(object value)
  376. {
  377. throw new InvalidOperationException();
  378. }
  379. public void Clear()
  380. {
  381. throw new InvalidOperationException();
  382. }
  383. public bool Contains(object value)
  384. {
  385. for (ISeq s = seq(); s != null; s = s.next())
  386. if (Util.equiv(s.first(), value))
  387. return true;
  388. return false;
  389. }
  390. public int IndexOf(object value)
  391. {
  392. ISeq s = seq();
  393. for (int i = 0; s != null; s = s.next(), i++)
  394. if (Util.equiv(s.first(), value))
  395. return i;
  396. return -1;
  397. }
  398. public void Insert(int index, object value)
  399. {
  400. throw new InvalidOperationException();
  401. }
  402. public bool IsFixedSize
  403. {
  404. get { return true; }
  405. }
  406. public bool IsReadOnly
  407. {
  408. get { return true; }
  409. }
  410. public void Remove(object value)
  411. {
  412. throw new InvalidOperationException();
  413. }
  414. public void RemoveAt(int index)
  415. {
  416. throw new InvalidOperationException();
  417. }
  418. public object this[int index]
  419. {
  420. get
  421. {
  422. return RT.nth(this,index);
  423. }
  424. set
  425. {
  426. throw new InvalidOperationException();
  427. }
  428. }
  429. #endregion
  430. }
  431. }
  432. }