LList.java 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. // FIX BRL's use to toString
  2. // Copyright (c) 2001, 2002, 2003 Per M.A. Bothner and Brainfood Inc.
  3. // This is free software; for terms and warranty disclaimer see ./COPYING.
  4. package gnu.lists;
  5. import gnu.kawa.util.HashUtils;
  6. import java.io.*;
  7. /**
  8. * Semi-abstract class for traditions Lisp-style lists.
  9. * A list is implemented as a chain of Pair objects, where the
  10. * 'car' field of the Pair points to a data element, and the 'cdr'
  11. * field points to the next Pair. (The names 'car' and 'cdr' are
  12. * historical; they refer to hardware on machines form the 60's.)
  13. * Includes singleton static Empty, and the Pair sub-class.
  14. * @author Per Bothner
  15. */
  16. public class LList extends ExtSequence<Object>
  17. implements Sequence<Object>, Externalizable, Comparable
  18. {
  19. /** Do not use - only public for serialization! */
  20. public LList () { }
  21. static public final EmptyList Empty = EmptyList.emptyList;
  22. /**
  23. * A safe function to count the length of a list.
  24. * @param obj the putative list to measure
  25. * @param allowOtherSequence if a non-List Sequence is seen, allow that
  26. * @return the length, or -1 for a circular list, or -2 for a dotted list
  27. */
  28. static public int listLength(Object obj, boolean allowOtherSequence)
  29. {
  30. // Based on list-length implementation in
  31. // Guy L Steele jr: "Common Lisp: The Language", 2nd edition, page 414
  32. int n = 0;
  33. Object slow = obj;
  34. Object fast = obj;
  35. for (;;)
  36. {
  37. if (fast == Empty)
  38. return n;
  39. if (! (fast instanceof Pair))
  40. {
  41. if (fast instanceof Sequence && allowOtherSequence)
  42. {
  43. int j = ((Sequence) fast).size ();
  44. return j >= 0 ? n + j : j;
  45. }
  46. return -2;
  47. }
  48. Pair fast_pair = (Pair) fast;
  49. Object fast_cdr = fast_pair.getCdr();
  50. if (fast_cdr == Empty)
  51. return n+1;
  52. if (fast == slow && n > 0)
  53. return -1;
  54. if (! (fast_cdr instanceof Pair))
  55. {
  56. n++;
  57. fast = fast_cdr;
  58. continue;
  59. }
  60. if (!(slow instanceof Pair))
  61. return -2;
  62. slow = ((Pair)slow).getCdr();
  63. fast = ((Pair)fast_cdr).getCdr();
  64. n += 2;
  65. }
  66. }
  67. public boolean equals (Object obj)
  68. {
  69. // Over-ridden in Pair!
  70. return this == obj;
  71. }
  72. public int compareTo(Object obj)
  73. { // Over-ridden in Pair!
  74. return obj == Empty ? 0 : -1;
  75. }
  76. public int size()
  77. {
  78. // Over-ridden in Pair!
  79. return 0;
  80. }
  81. public boolean isEmpty()
  82. {
  83. // Over-ridden in Pair!
  84. return true;
  85. }
  86. public SeqPosition getIterator(int index)
  87. {
  88. return new LListPosition(this, index, false);
  89. }
  90. public int createPos(int index, boolean isAfter)
  91. {
  92. ExtPosition pos = new LListPosition(this, index, isAfter);
  93. return PositionManager.manager.register(pos);
  94. }
  95. public int createRelativePos(int pos, int delta, boolean isAfter)
  96. {
  97. boolean old_after = isAfterPos(pos);
  98. if (delta < 0 || pos == 0)
  99. return super.createRelativePos(pos, delta, isAfter);
  100. if (delta == 0)
  101. {
  102. if (isAfter == old_after)
  103. return copyPos(pos);
  104. if (isAfter && ! old_after)
  105. return super.createRelativePos(pos, delta, isAfter);
  106. }
  107. if (pos < 0)
  108. throw new IndexOutOfBoundsException();
  109. LListPosition old = (LListPosition) PositionManager.getPositionObject(pos);
  110. if (old.xpos == null)
  111. return super.createRelativePos(pos, delta, isAfter);
  112. LListPosition it = new LListPosition(old);
  113. Object it_xpos = it.xpos;
  114. int it_ipos = it.ipos;
  115. if (isAfter && ! old_after)
  116. {
  117. delta--;
  118. it_ipos += 3;
  119. }
  120. if (! isAfter && old_after)
  121. {
  122. delta++;
  123. it_ipos -= 3;
  124. }
  125. for (;;)
  126. {
  127. if (! (it_xpos instanceof Pair))
  128. throw new IndexOutOfBoundsException();
  129. if (--delta < 0)
  130. break;
  131. Pair p = (Pair) it_xpos;
  132. it_ipos += 2;
  133. it_xpos = p.getCdr();
  134. }
  135. it.ipos = it_ipos;
  136. it.xpos = it_xpos;
  137. return PositionManager.manager.register(it);
  138. }
  139. public boolean hasNext (int ipos)
  140. {
  141. return false; // Overridden in Pair.
  142. }
  143. public int nextPos (int ipos)
  144. {
  145. return 0; // Overridden in Pair.
  146. }
  147. public Object getPosNext (int ipos)
  148. {
  149. return eofValue; // Overridden in Pair.
  150. }
  151. public Object getPosPrevious (int ipos)
  152. {
  153. return eofValue; // Overridden in Pair.
  154. }
  155. protected void setPosNext(int ipos, Object value)
  156. {
  157. if (ipos <= 0)
  158. {
  159. if (ipos == -1 || ! (this instanceof Pair))
  160. throw new IndexOutOfBoundsException();
  161. ((Pair) this).car = value;
  162. }
  163. else
  164. PositionManager.getPositionObject(ipos).setNext(value);
  165. }
  166. protected void setPosPrevious(int ipos, Object value)
  167. {
  168. if (ipos <= 0)
  169. {
  170. if (ipos == 0 || ! (this instanceof Pair))
  171. throw new IndexOutOfBoundsException();
  172. ((Pair) this).lastPair().car = value;
  173. }
  174. else
  175. PositionManager.getPositionObject(ipos).setPrevious(value);
  176. }
  177. public Object get (int index)
  178. {
  179. throw new IndexOutOfBoundsException();
  180. }
  181. /* Count the length of a list.
  182. * Note: does not catch circular lists!
  183. * @param arg the list to count
  184. * @return the length
  185. */
  186. static public final int length (Object arg)
  187. {
  188. int count = 0;
  189. for ( ; arg instanceof Pair; arg = ((Pair)arg).getCdr())
  190. count++;
  191. return count;
  192. }
  193. public int boundedHash(int seed, int limit) {
  194. // Compatible with the AbstractSequence.boundedHash for true lists.
  195. Object list = this;
  196. int sublimit = limit >> 1;
  197. int count = 0;
  198. while (list instanceof Pair) {
  199. if (++count > limit)
  200. break;
  201. Pair pair = (Pair) list;
  202. int h = HashUtils.boundedHash(pair.getCar(), 0, sublimit);
  203. seed = HashUtils.murmur3step(seed, h);
  204. list = pair.getCdr();
  205. }
  206. if (--limit >= 0 && list != LList.Empty && list != null) {
  207. int h = HashUtils.boundedHash(list, 0, sublimit);
  208. seed = HashUtils.murmur3step(seed, h);
  209. count++;
  210. }
  211. return HashUtils.murmur3finish(seed, count);
  212. }
  213. public int hashCode()
  214. {
  215. // Compatible with the AbstractSequence hashCode for true lists.
  216. int hash = 1;
  217. Object list = this;
  218. while (list instanceof Pair)
  219. {
  220. Pair pair = (Pair) list;
  221. Object obj = pair.getCar();
  222. hash = 31*hash + (obj==null ? 0 : obj.hashCode());
  223. list = pair.getCdr();
  224. }
  225. if (list != LList.Empty && list != null)
  226. hash = hash ^ list.hashCode();
  227. return hash;
  228. }
  229. public static LList makeList (java.util.List vals)
  230. {
  231. java.util.Iterator e = vals.iterator();
  232. LList result = LList.Empty;
  233. Pair last = null;
  234. while (e.hasNext())
  235. {
  236. Pair pair = new Pair(e.next(), LList.Empty);
  237. if (last == null)
  238. result = pair;
  239. else
  240. last.cdr = pair;
  241. last = pair;
  242. }
  243. return result;
  244. }
  245. public static LList makeList (Object[] vals, int offset, int length)
  246. {
  247. LList result = LList.Empty;
  248. for (int i = length; --i >= 0; )
  249. result = new Pair (vals[offset+i], result);
  250. return result;
  251. }
  252. public static LList makeList (Object[] vals, int offset)
  253. {
  254. /* DEBUGGING:
  255. System.err.print("makeList [");
  256. for (int i = 0; i < vals.length; i++)
  257. {
  258. if (i > 0)
  259. System.err.print(", ");
  260. System.err.print(vals[i]);
  261. }
  262. System.err.println("], offset:"+offset);
  263. */
  264. LList result = LList.Empty;
  265. for (int i = vals.length - offset; --i >= 0; )
  266. result = new Pair (vals[offset+i], result);
  267. return result;
  268. }
  269. /* FIXME
  270. public FVector toVector ()
  271. {
  272. int len = size();
  273. Object[] values = new Object[len];
  274. Object list = this;
  275. for (int i=0; i < len; i++)
  276. {
  277. Pair pair = (Pair) list;
  278. values[i] = pair.car;
  279. list = pair.cdr;
  280. }
  281. return new FVector (values);
  282. }
  283. */
  284. public void consume(Consumer out)
  285. {
  286. Object list = this;
  287. out.startElement("list");
  288. while (list instanceof Pair)
  289. {
  290. if (list != this)
  291. out.write(' ');
  292. Pair pair = (Pair) list;
  293. out.writeObject(pair.getCar());
  294. list = pair.getCdr();
  295. }
  296. if (list != Empty)
  297. {
  298. out.write(' ');
  299. out.write(". ");
  300. out.writeObject(checkNonList(list));
  301. }
  302. out.endElement();
  303. }
  304. public void readExternal(ObjectInput in)
  305. throws IOException, ClassNotFoundException
  306. {
  307. }
  308. /**
  309. * @serialData Write nothing.
  310. * (Don't need to write anything.)
  311. */
  312. public void writeExternal(ObjectOutput out) throws IOException
  313. {
  314. }
  315. public Object readResolve() throws ObjectStreamException
  316. {
  317. return Empty;
  318. }
  319. public static Pair list1(Object arg1)
  320. {
  321. return new Pair(arg1, LList.Empty);
  322. }
  323. public static Pair list2(Object arg1, Object arg2)
  324. {
  325. return new Pair(arg1, new Pair(arg2, LList.Empty));
  326. }
  327. public static Pair list3(Object arg1, Object arg2, Object arg3)
  328. {
  329. return new Pair(arg1, new Pair(arg2, new Pair(arg3, LList.Empty)));
  330. }
  331. public static Pair list4(Object arg1, Object arg2, Object arg3, Object arg4)
  332. {
  333. return new Pair(arg1, new Pair(arg2,
  334. new Pair(arg3, new Pair (arg4,
  335. LList.Empty))));
  336. }
  337. /** Utility function used by compiler when inlining `list'. */
  338. public static Pair chain1 (Pair old, Object arg1)
  339. {
  340. Pair p1 = new Pair(arg1, LList.Empty);
  341. old.cdr = p1;
  342. return p1;
  343. }
  344. /** Utility function used by compiler when inlining `list'. */
  345. public static Pair chain4 (Pair old, Object arg1, Object arg2,
  346. Object arg3, Object arg4)
  347. {
  348. Pair p4 = new Pair(arg4, LList.Empty);
  349. old.cdr = new Pair(arg1, new Pair(arg2, new Pair(arg3, p4)));
  350. return p4;
  351. }
  352. /** Reverse a list in place, by modifying the cdr fields. */
  353. public static LList reverseInPlace(Object list)
  354. {
  355. // Algorithm takes from reverse function in gcc's tree.c.
  356. LList prev = Empty;
  357. while (list != Empty)
  358. {
  359. Pair pair = (Pair) list;
  360. list = pair.cdr;
  361. pair.cdr = prev;
  362. prev = pair;
  363. }
  364. return prev;
  365. }
  366. /** SRFI-1's cons* and Common Lisp's list* function. */
  367. public static Object consX (Object[] args)
  368. {
  369. // Error if args.length==0.
  370. Object first = args[0];
  371. int n = args.length - 1;
  372. if (n <= 0)
  373. return first;
  374. Pair result = new Pair(first, null);
  375. Pair prev = result;
  376. for (int i = 1; i < n; i++)
  377. {
  378. Pair next = new Pair(args[i], null);
  379. prev.cdr = next;
  380. prev = next;
  381. }
  382. prev.cdr = args[n];
  383. return result;
  384. }
  385. public String toString ()
  386. {
  387. Object rest = this;
  388. int i = 0;
  389. StringBuffer sbuf = new StringBuffer(100);
  390. sbuf.append('(');
  391. for (;;)
  392. {
  393. if (rest == Empty)
  394. break;
  395. if (i > 0)
  396. sbuf.append(' ');
  397. if (i >= 10)
  398. {
  399. sbuf.append("...");
  400. break;
  401. }
  402. if (rest instanceof Pair)
  403. {
  404. Pair pair = (Pair) rest;
  405. sbuf.append(pair.getCar());
  406. rest = pair.getCdr();
  407. }
  408. else
  409. {
  410. sbuf.append(". ");
  411. sbuf.append(checkNonList(rest));
  412. break;
  413. }
  414. i++;
  415. }
  416. sbuf.append(')');
  417. return sbuf.toString();
  418. }
  419. /** Helper to protect against pathological LLists (neithr Pair nor Empty). */
  420. public static Object checkNonList (Object rest)
  421. {
  422. return rest instanceof LList ? "#<not a pair>" : rest;
  423. }
  424. }