LListPosition.java 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. // Copyright (c) 2001, 2002, 2003 Per M.A. Bothner and Brainfood Inc.
  2. // This is free software; for terms and warranty disclaimer see ./COPYING.
  3. package gnu.lists;
  4. import java.util.NoSuchElementException;
  5. /** LListPosition - a SeqPosition for LLists.
  6. * Normally, we just use an int pos to indicate a position in a
  7. * sequence. But for linked lists that would be very inefficient.
  8. * So this sub-class in addition uses an xpos field to point to the
  9. * current Pair. However, we do so in a non-obvious way. After a next(),
  10. * xpos points to *two* Pairs before the logical iterator position
  11. * (the cursor). This is because of the requirement for remove(),
  12. * which needs to be able to remove the element *before* the cursor.
  13. * But to unlink that element, we need to change the 'next' field
  14. * of the Pair before that again.
  15. * However, after a call to 'previous', we cannot cheaply move the
  16. * xpos pointer backwards, so we leave it as is. Therefore, we
  17. * get the rule that when isAfter() is false the cursor position is
  18. * after the Pair pointed by xpos; when isAfter() is true then
  19. * the cursor position is after the Pair ((Pair) xpos).cdr).
  20. * If the cursor position is too early in the list to satisfy this
  21. * invariant, then xpos==null.
  22. */
  23. class LListPosition extends ExtPosition<Object, LList>
  24. {
  25. Object xpos;
  26. public LListPosition (LListPosition old)
  27. {
  28. sequence = old.sequence;
  29. ipos = old.ipos;
  30. xpos = old.xpos;
  31. }
  32. public LListPosition copy()
  33. {
  34. return new LListPosition(this);
  35. }
  36. public LListPosition (LList seq, int index, boolean isAfter)
  37. {
  38. set(seq, index, isAfter);
  39. }
  40. public void set (LList seq, int index, boolean isAfter)
  41. {
  42. sequence = seq;
  43. ipos = (index << 1) | (isAfter ? 1 : 0);
  44. int skip = index;
  45. if (isAfter)
  46. {
  47. skip -= 2;
  48. }
  49. else
  50. {
  51. skip -= 1;
  52. }
  53. if (skip >= 0)
  54. {
  55. Object p = seq;
  56. while (--skip >= 0)
  57. {
  58. p = ((Pair) p).getCdr();
  59. }
  60. xpos = p;
  61. }
  62. else
  63. xpos = null;
  64. }
  65. public boolean hasNext()
  66. {
  67. Object next;
  68. if (xpos == null)
  69. {
  70. if ((ipos >> 1) == 0)
  71. return sequence != LList.Empty;
  72. return ((Pair) sequence).getCdr() != LList.Empty;
  73. }
  74. else
  75. next = ((Pair) xpos).getCdr();
  76. if ((ipos & 1) > 0) // if isAfter
  77. next = ((Pair) next).getCdr();
  78. return next != LList.Empty;
  79. }
  80. public boolean hasPrevious()
  81. {
  82. return (ipos >>> 1) != 0;
  83. }
  84. /** Get the Pair whose car contains the next element, or null. */
  85. public Pair getNextPair ()
  86. {
  87. int isAfter = (ipos & 1);
  88. Object next;
  89. if (isAfter > 0)
  90. {
  91. if (xpos == null)
  92. {
  93. next = sequence;
  94. if ((ipos >> 1) != 0)
  95. next = ((Pair) next).getCdr();
  96. }
  97. else
  98. next = ((Pair) (((Pair) xpos).getCdr())).getCdr();
  99. }
  100. else
  101. {
  102. if (xpos == null)
  103. next = sequence;
  104. else
  105. next = ((Pair) xpos).getCdr();
  106. }
  107. if (next == LList.Empty)
  108. return null;
  109. return (Pair) next;
  110. }
  111. public Object getNext ()
  112. {
  113. Pair pair = getNextPair();
  114. return pair == null ? LList.eofValue : pair.getCar();
  115. }
  116. public void setNext (Object value)
  117. {
  118. Pair pair = getNextPair();
  119. pair.car = value;
  120. }
  121. /** Get the Pair whose car contains the previous element, or null. */
  122. public Pair getPreviousPair ()
  123. {
  124. int isAfter = (ipos & 1);
  125. Object p = xpos;
  126. if (isAfter > 0)
  127. p = p == null ? sequence : ((Pair) p).getCdr();
  128. else if (p == null)
  129. return null;
  130. if (p == LList.Empty)
  131. return null;
  132. return (Pair) p;
  133. }
  134. public Object getPrevious ()
  135. {
  136. Pair pair = getPreviousPair();
  137. return pair == null ? LList.eofValue : pair.getCar();
  138. }
  139. public void setPrevious(Object value)
  140. {
  141. Pair pair = getPreviousPair();
  142. pair.car = value;
  143. }
  144. public int nextIndex ()
  145. {
  146. return ipos >> 1;
  147. }
  148. /** @Override */
  149. public Object next() {
  150. Pair pair = getNextPair();
  151. if (pair == null || ! gotoNext())
  152. throw new NoSuchElementException();
  153. return pair.getCar();
  154. }
  155. public boolean gotoNext() {
  156. boolean isAfter = (ipos & 1) != 0;
  157. int old_i = ipos;
  158. Object xp = xpos;
  159. if (xp != null)
  160. {
  161. if (isAfter)
  162. xp = ((Pair) xp).getCdr();
  163. if (((Pair) xp).getCdr() == LList.Empty)
  164. return false;
  165. xpos = xp;
  166. ipos = (ipos | 1) + 2;
  167. }
  168. else if ((ipos >> 1) == 0) // position is 0
  169. {
  170. if (sequence == LList.Empty)
  171. return false;
  172. ipos = (1 << 1) | 1;
  173. }
  174. else // position is 1, iAfter must be true
  175. {
  176. xp = sequence;
  177. if (((Pair) xp).getCdr() == LList.Empty)
  178. return false;
  179. ipos = (2 << 1) | 1;
  180. xpos = xp;
  181. }
  182. return true;
  183. }
  184. public boolean gotoPrevious()
  185. {
  186. if (ipos >>> 1 == 0)
  187. return false;
  188. if ((ipos & 1) != 0) // isAfter()
  189. {
  190. // Decrement index; clear isAfter bit.
  191. ipos -= 3;
  192. return true;
  193. }
  194. int index = nextIndex();
  195. set((LList) sequence, index - 1, false);
  196. return true;
  197. }
  198. public String toString()
  199. {
  200. StringBuffer sbuf = new StringBuffer();
  201. sbuf.append("LListPos[");
  202. //sbuf.append(super.toString());
  203. sbuf.append("index:");
  204. sbuf.append(ipos);
  205. if (isAfter())
  206. sbuf.append(" after");
  207. if (position >= 0)
  208. {
  209. sbuf.append(" position:");
  210. sbuf.append(position);
  211. }
  212. sbuf.append(']');
  213. return sbuf.toString();
  214. }
  215. }