TreePosition.java 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. // Copyright (c) 2001 Per M.A. Bothner and Brainfood Inc.
  2. // This is free software; for terms and warranty disclaimer see ./COPYING.
  3. package gnu.lists;
  4. /**
  5. * A position that can also go down and up in a tree.
  6. * A TreePosition is a stack of positions. The "current" position
  7. * (i.e. the one you get if you tree the TreePosition as a SeqPosition)
  8. * is that in the innermost containing sequence.
  9. *
  10. * Normally, the "current" element is (the one following) a position in a
  11. * sequence. As a special (initial case), we may want to treat the
  12. * entire sequence is the "current element". This is represented by depth==-1
  13. * and xpos set to the root element (which need not actually be a sequence).
  14. */
  15. public class TreePosition extends SeqPosition implements Cloneable
  16. {
  17. /** Used when depth==-1 to indicate the "entire" object.
  18. * Usually an AbstractSequence, but need not be. */
  19. private Object xpos;
  20. /** Stack of pushed values for sequence. */
  21. AbstractSequence[] sstack;
  22. /** Stack of pushed values for iposition. */
  23. int[] istack;
  24. /** Depth of the above stacks.
  25. * Note that getDepth returns depth+1; this should perhaps match. */
  26. int depth;
  27. /** Start of stacks - anything below 'start' is ignored.
  28. * This is useful for pushing/pop positions without object allocation. */
  29. int start;
  30. public TreePosition()
  31. {
  32. depth = -1;
  33. }
  34. /** Not a position *in* a sequence, but the current element is the entire sequence. */
  35. public TreePosition(Object root)
  36. {
  37. xpos = root;
  38. depth = -1;
  39. }
  40. public TreePosition(AbstractSequence seq, int index)
  41. {
  42. super(seq, index, false);
  43. }
  44. public TreePosition (TreePosition pos)
  45. {
  46. set(pos);
  47. }
  48. public Object clone ()
  49. {
  50. return new TreePosition(this);
  51. }
  52. public void set (TreePosition position)
  53. {
  54. release();
  55. int d = position.depth;
  56. depth = d;
  57. if (d < 0)
  58. {
  59. xpos = position.xpos;
  60. return;
  61. }
  62. if (sstack == null || sstack.length <= d)
  63. sstack = new AbstractSequence[d + 10];
  64. if (istack == null || istack.length <= d)
  65. istack = new int[d + 10];
  66. AbstractSequence seq;
  67. int i;
  68. for (i = 0; i < depth; i++)
  69. {
  70. int j = i + position.start;
  71. seq = position.sstack[j];
  72. sstack[depth-1] = seq;
  73. istack[depth - i] = seq.copyPos(position.istack[j]);
  74. }
  75. seq = position.sequence;
  76. sequence = seq;
  77. ipos = seq.copyPos(position.ipos);
  78. }
  79. /** Number of ancestor sequences, including current sequence. */
  80. public int getDepth()
  81. {
  82. return depth + 1;
  83. }
  84. /** Get the "root document". */
  85. public AbstractSequence getRoot()
  86. {
  87. return depth == 0 ? sequence : sstack[start];
  88. }
  89. public Object getPosNext()
  90. {
  91. return sequence == null ? xpos : sequence.getPosNext(ipos);
  92. }
  93. public void push(AbstractSequence child, int iposChild)
  94. {
  95. int d = depth + start;
  96. if (d >= 0)
  97. {
  98. if (d == 0)
  99. {
  100. istack = new int[8];
  101. sstack = new AbstractSequence[8];
  102. }
  103. else if (d >= istack.length)
  104. {
  105. int ndepth = 2 * d;
  106. int[] itemp = new int[ndepth];
  107. Object[] xtemp = new Object[ndepth];
  108. AbstractSequence[] stemp = new AbstractSequence[ndepth];
  109. System.arraycopy(istack, 0, itemp, 0, depth);
  110. System.arraycopy(sstack, 0, stemp, 0, depth);
  111. istack = itemp;
  112. sstack = stemp;
  113. }
  114. sstack[d] = sequence;
  115. istack[d] = ipos;
  116. }
  117. depth++;
  118. sequence = child;
  119. ipos = iposChild;
  120. }
  121. public void pop()
  122. {
  123. sequence.releasePos(ipos);
  124. popNoRelease();
  125. }
  126. public void popNoRelease()
  127. {
  128. if (--depth < 0)
  129. {
  130. xpos = sequence;
  131. sequence = null;
  132. }
  133. else
  134. {
  135. sequence = sstack[start+depth];
  136. ipos = istack[start+depth];
  137. }
  138. }
  139. public final boolean gotoParent()
  140. {
  141. return sequence == null ? false : sequence.gotoParent(this);
  142. }
  143. /** Set position before first child (of the element following position).
  144. * @return true if there is a child sequence (which might be empty);
  145. * false if current position is end of sequence or following element
  146. * is atomic (cannot have children).
  147. */
  148. public boolean gotoChildrenStart()
  149. {
  150. if (sequence == null)
  151. {
  152. if (! (xpos instanceof AbstractSequence))
  153. return false;
  154. depth = 0;
  155. sequence = (AbstractSequence) xpos;
  156. setPos(sequence.startPos());
  157. }
  158. else
  159. {
  160. if (! sequence.gotoChildrenStart(this))
  161. return false;
  162. }
  163. return true;
  164. }
  165. /** Set position before first attribute (of the element following position).
  166. * This is used to iterate through the sequence of attributes.
  167. */
  168. public boolean gotoAttributesStart()
  169. {
  170. if (sequence == null)
  171. {
  172. if (xpos instanceof AbstractSequence)
  173. {
  174. // ??? FIXME
  175. }
  176. return false;
  177. }
  178. return sequence.gotoAttributesStart(this);
  179. }
  180. /*
  181. public boolean gotoAttribute(Object name)
  182. {
  183. return sequence.gotoAttribute(this);
  184. }
  185. */
  186. /** Get the value of an ancestor node.
  187. * @param up the number parents to go up.
  188. * @return if up is 0, same getNext. Otherwise get parent
  189. * applied as specified.
  190. */
  191. public Object getAncestor(int up)
  192. {
  193. if (up == 0)
  194. return sequence.getPosNext(ipos);
  195. int i = depth - up;
  196. if (i <= 0)
  197. return getRoot();
  198. i += start;
  199. return sstack[i].getPosNext(istack[i]);
  200. }
  201. public void release()
  202. {
  203. while (sequence != null)
  204. {
  205. sequence.releasePos(ipos);
  206. pop();
  207. }
  208. xpos = null;
  209. }
  210. /** Copy this position into pos. */
  211. /*
  212. public void clone (Position pos)
  213. {
  214. // FIXME!
  215. }
  216. public Object clone()
  217. {
  218. TreePosition pos = new TreePosition();
  219. clone(pos);
  220. return pos;
  221. }
  222. */
  223. public void dump()
  224. {
  225. System.err.println("TreePosition dump depth:"+depth+" start:"+start);
  226. for (int i = 0; i <= depth; i++)
  227. {
  228. AbstractSequence seq = i==0 ? sequence : sstack[depth-i];
  229. System.err.print("#"+i+" seq:"+seq);
  230. System.err.println(" ipos:" + (i == 0 ? ipos : istack[depth-i]));
  231. }
  232. }
  233. }