AbstractSequence.java 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953
  1. // Copyright (c) 2001, 2002, 2003, 2005 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 gnu.kawa.util.HashUtils;
  5. import java.util.*;
  6. /**
  7. * A collection of default methods for implementing sequence-like classes.
  8. *
  9. * Additionally, a sequence may have zero or more attributes, which are
  10. * name-value pairs. A sequence may also have a named "type". These
  11. * extensions are to support XML functionality - it might be cleaner to
  12. * move them to a sub-class of Sequence or some interface.
  13. *
  14. * Many of the protected methods in Sequence (such as nextIndex) are
  15. * only intended to be called from SeqPosition or TreePosition, see those.
  16. *
  17. * @author Per Bothner
  18. */
  19. public abstract class AbstractSequence<E>
  20. {
  21. public static final int[] noInts = new int[0];
  22. public int size() {
  23. if (rank() == 1) return getSize(0);
  24. throw unsupported("size");
  25. }
  26. public int getSize() {
  27. int sz = 1;
  28. for (int r = rank(); --r >= 0; )
  29. sz *= getSize(r);
  30. return sz;
  31. }
  32. public boolean isEmpty()
  33. {
  34. return size() == 0;
  35. }
  36. public int rank()
  37. {
  38. return 1;
  39. }
  40. protected void checkRank(int i) {
  41. if (i != rank())
  42. throw badRank(i);
  43. }
  44. protected RuntimeException badRank(int i) {
  45. return new RuntimeException("wrong number of indexes "+i+" to "+rank()+"-rank array");
  46. }
  47. // FIXME remove this - some implementations needed
  48. public Array<E> asImmutable() { throw unsupported("asImmutable"); }
  49. public E get() { return getRaw(effectiveIndex()); }
  50. public E get(int i) {
  51. return getRaw(effectiveIndex(i));
  52. }
  53. public E get(int i, int j) { return getRaw(effectiveIndex(i,j)); }
  54. public E get(int i, int j, int k, int... rest) {
  55. return getRaw(effectiveIndex(i, j, k, rest)); }
  56. public E get(int[] indexes) {
  57. return getRaw(effectiveIndex(indexes));
  58. }
  59. protected void checkCanWrite () {
  60. }
  61. public E getRowMajor(int index) {
  62. if (rank() == 1)
  63. return get(index);
  64. if (this instanceof Array)
  65. return Arrays.getRowMajor((Array<E>) this, index);
  66. throw unsupportedException("getRowMajor");
  67. }
  68. public int effectiveIndex() {
  69. checkRank(0);
  70. return 0;
  71. }
  72. public int effectiveIndex(int index) {
  73. checkRank(1);
  74. return index - getLowBound(0);
  75. }
  76. public int effectiveIndex(int i, int j) {
  77. checkRank(2);
  78. return (i - getLowBound(0)) * getSize(1) + (j - getLowBound(1));
  79. }
  80. public int effectiveIndex(int i, int j, int k, int... rest) {
  81. int r = rest.length;
  82. checkRank(3+r);
  83. int eff = 0;
  84. int stride = 1;
  85. while (--r >= 0) {
  86. eff += (rest[r] - getLowBound(3+r)) * stride;
  87. stride *= getSize(3+r);
  88. }
  89. eff += (k - getLowBound(2)) * stride;
  90. stride *= getSize(2);
  91. eff += (j - getLowBound(1)) * stride;
  92. stride *= getSize(1);
  93. eff += (i - getLowBound(0)) * stride;
  94. return eff;
  95. }
  96. public int effectiveIndex(int[] indexes) {
  97. int ilength = indexes.length;
  98. switch (indexes.length) {
  99. case 0:
  100. return effectiveIndex();
  101. case 1:
  102. return effectiveIndex(indexes[0]);
  103. case 2:
  104. return effectiveIndex(indexes[0], indexes[1]);
  105. default:
  106. int[] rest;
  107. if (ilength == 3)
  108. rest = noInts;
  109. else {
  110. rest = new int[ilength-3];
  111. System.arraycopy(indexes, 3, rest, 0, ilength-3);
  112. }
  113. return effectiveIndex(indexes[0], indexes[1], indexes[2], rest);
  114. }
  115. }
  116. public E getRaw(int index) { throw unsupported("getRaw"); }
  117. protected void setBuffer(Object obj) { throw unsupported("setBuffer"); }
  118. /** Given an "effective index", set selected element. */
  119. public void setRaw(int index, E value) { throw unsupported("setRaw"); }
  120. public boolean getBooleanRaw(int index) {
  121. Object value = getRaw(index);
  122. return value != null && ((Boolean) value).booleanValue();
  123. }
  124. public char getCharRaw(int index) {
  125. return ((Character) getRaw(index)).charValue();
  126. }
  127. public byte getByteRaw(int index) {
  128. return ((Number) getRaw(index)).byteValue();
  129. }
  130. public short getShortRaw(int index) {
  131. return ((Number) getRaw(index)).shortValue();
  132. }
  133. public int getIntRaw(int index) {
  134. return ((Number) getRaw(index)).intValue();
  135. }
  136. public long getLongRaw(int index) {
  137. return ((Number) getRaw(index)).longValue();
  138. }
  139. public float getFloatRaw(int index) {
  140. return ((Number) getRaw(index)).floatValue();
  141. }
  142. public double getDoubleRaw(int index) {
  143. return ((Number) getRaw(index)).doubleValue();
  144. }
  145. public int getInt() { return getIntRaw(effectiveIndex()); }
  146. public int getInt(int i) { return getIntRaw(effectiveIndex(i)); }
  147. public int getInt(int i, int j) { return getIntRaw(effectiveIndex(i,j)); }
  148. public int getInt(int i, int j, int k, int... rest) {
  149. return getIntRaw(effectiveIndex(i, j, k, rest)); }
  150. public int getInt(int[] indexes) {
  151. return getIntRaw(effectiveIndex(indexes));
  152. }
  153. public void set(int[] indexes, E value) {
  154. checkCanWrite();
  155. setRaw(effectiveIndex(indexes), value);
  156. }
  157. public int getLowBound(int dim)
  158. {
  159. return 0;
  160. }
  161. public int getSize (int dim)
  162. {
  163. return dim==0 ? size() : 1;
  164. }
  165. public int getElementKind() { return Sequence.OBJECT_VALUE; }
  166. protected RuntimeException unsupported (String text)
  167. {
  168. return unsupportedException(getClass().getName()
  169. + " does not implement " + text);
  170. }
  171. public static RuntimeException unsupportedException (String text)
  172. {
  173. return new UnsupportedOperationException(text);
  174. }
  175. public E set(int index, E value) {
  176. checkCanWrite();
  177. int effi = effectiveIndex(index);
  178. E old = (E) getRaw(effi);
  179. setRaw(effi, value);
  180. return old;
  181. }
  182. public void setAt(int index, E value) {
  183. checkCanWrite();
  184. setRaw(effectiveIndex(index), value);
  185. }
  186. public void fill(E value)
  187. {
  188. for (int i = startPos(); (i = nextPos(i)) != 0; )
  189. setPosPrevious(i, value);
  190. }
  191. public void fillPosRange(int fromPos, int toPos, E value)
  192. {
  193. int i = copyPos(fromPos);
  194. for (; compare(i, toPos) < 0; i = nextPos(i))
  195. setPosNext(i, value);
  196. releasePos(i);
  197. }
  198. public void fill(int fromIndex, int toIndex, E value)
  199. {
  200. int i = createPos(fromIndex, false);
  201. int limit = createPos(toIndex, true);
  202. for (; compare(i, limit) < 0; i = nextPos(i))
  203. setPosNext(i, value);
  204. releasePos(i);
  205. releasePos(limit);
  206. }
  207. // FIXME?
  208. //public final Object elementAt (int index) { return get(index); }
  209. /** See java.util.List. */
  210. public int indexOf(Object o)
  211. {
  212. int i = 0;
  213. for (int iter = startPos(); (iter = nextPos(iter)) != 0; i++)
  214. {
  215. Object v = getPosPrevious(iter);
  216. if (o==null ? v==null : o.equals(v))
  217. {
  218. releasePos(iter);
  219. return i;
  220. }
  221. }
  222. return -1;
  223. }
  224. /** See java.util.List. */
  225. public int lastIndexOf(Object o)
  226. {
  227. // FIXME use iterator?
  228. for (int n = size(); --n >= 0; )
  229. {
  230. Object e = get(n);
  231. if (o==null ? e == null : o.equals(e))
  232. return n;
  233. }
  234. return -1;
  235. }
  236. /** Get next matching child or descendent (ignoring attributes).
  237. * @param startPos starting position
  238. * @param type a test (predicate) to apply to selected elements
  239. * @param endPos stop before endPos
  240. * @param descend if true do depth-first traversal.
  241. * @return poistion of next match or 0 if none found
  242. */
  243. public int nextMatching(int startPos, ItemPredicate type,
  244. int endPos, boolean descend)
  245. {
  246. if (descend)
  247. throw unsupported("nextMatching with descend");
  248. int ipos = startPos;
  249. for (;;)
  250. {
  251. if (compare(ipos, endPos) >= 0)
  252. return 0;
  253. ipos = nextPos(ipos);
  254. if (type.isInstancePos(this, ipos))
  255. return ipos;
  256. }
  257. }
  258. /** See java.util.List. */
  259. public boolean contains(Object o)
  260. {
  261. return indexOf(o) >= 0;
  262. }
  263. /** See java.util.List. */
  264. public boolean containsAll(Collection<?> c)
  265. {
  266. Iterator<?> i = c.iterator();
  267. while (i.hasNext())
  268. {
  269. Object e = i.next();
  270. if (! contains(e))
  271. return false;
  272. }
  273. return true;
  274. }
  275. public final Enumeration<E> elements()
  276. {
  277. return getIterator(0);
  278. }
  279. public final SeqPosition<E, AbstractSequence<E>> getIterator()
  280. {
  281. return getIterator(0);
  282. }
  283. public SeqPosition<E, AbstractSequence<E>> getIterator(int index)
  284. {
  285. return new SeqPosition<E,AbstractSequence<E>>(this, index, false);
  286. }
  287. public SeqPosition<E, AbstractSequence<E>> getIteratorAtPos(int ipos)
  288. {
  289. return new SeqPosition<E,AbstractSequence<E>>(this, copyPos(ipos));
  290. }
  291. public final Iterator<E> iterator()
  292. {
  293. return getIterator(0);
  294. }
  295. public final ListIterator<E> listIterator()
  296. {
  297. return getIterator(0);
  298. }
  299. public final ListIterator<E> listIterator(int index)
  300. {
  301. return getIterator(index);
  302. }
  303. /** Add a value at a specified Pos.
  304. * @return the updated Pos, which is after the inserted value..
  305. */
  306. protected int addPos (int ipos, E value)
  307. {
  308. throw unsupported("addPos");
  309. }
  310. /** See java.util.Collection. */
  311. public boolean add(E o)
  312. {
  313. addPos(endPos(), o);
  314. return true;
  315. }
  316. /** See java.util.List. */
  317. public void add(int index, E o)
  318. {
  319. int pos = createPos(index, false);
  320. addPos(pos, o);
  321. releasePos(pos);
  322. }
  323. /** See java.util.Collection. */
  324. public boolean addAll(Collection<? extends E> c)
  325. {
  326. return addAll(size(), c);
  327. }
  328. /** See java.util.Collection. */
  329. public boolean addAll(int index, Collection<? extends E> c)
  330. {
  331. boolean changed = false;
  332. int pos = createPos(index, false);
  333. for (Iterator<? extends E> it = c.iterator(); it.hasNext(); )
  334. {
  335. pos = addPos(pos, it.next());
  336. changed = true;
  337. }
  338. releasePos(pos);
  339. return changed;
  340. }
  341. /**
  342. * Remove one or more elements.
  343. * @param ipos position where elements should be removed
  344. * @param count if non-negative, remove that number of elements
  345. * following (poses, posNumber); if negative the negative of the number
  346. * of elements to remove before (poses, posNumber).
  347. * @exception java.lang.IndexOutOfBoundsException
  348. * if {@code (count >= 0 ? (index < 0 || index + count > size())
  349. * : (index + count < 0 || index > size()))},
  350. * where {@code index == nextIndex(ipos, xpos)}.
  351. */
  352. public void removePos(int ipos, int count)
  353. {
  354. int rpos = createRelativePos(ipos, count, false);
  355. if (count >= 0)
  356. removePosRange(ipos, rpos);
  357. else
  358. removePosRange(rpos, ipos);
  359. releasePos(rpos);
  360. }
  361. /** Remove a range where each end-point is a position in a container.
  362. * @param ipos0 start of range, as a poistion
  363. * @param ipos1 end of range
  364. * @exception java.lang.IndexOutOfBoundsException
  365. * if {@code nextIndex(ipos0) > nextIndex(ipos1)}
  366. * or {@code nextIndex(ipos0) < 0} or {@code nextIndex(ipos1) > size()}.
  367. */
  368. protected void removePosRange(int ipos0, int ipos1)
  369. {
  370. throw unsupported("removePosRange");
  371. }
  372. public E remove(int index)
  373. {
  374. if (index < 0 || index >= size())
  375. throw new IndexOutOfBoundsException();
  376. int ipos = createPos(index, false);
  377. E result = (E) getPosNext(ipos);
  378. removePos(ipos, 1);
  379. releasePos(ipos);
  380. return result;
  381. }
  382. public boolean remove(Object o)
  383. {
  384. int index = indexOf(o);
  385. if (index < 0)
  386. return false;
  387. int ipos = createPos(index, false);
  388. removePos(ipos, 1);
  389. releasePos(ipos);
  390. return true;
  391. }
  392. public boolean removeAll(Collection<?> c)
  393. {
  394. boolean changed = false;
  395. for (int iter = startPos(); (iter = nextPos(iter)) != 0; )
  396. {
  397. Object value = getPosPrevious(iter);
  398. if (c.contains(value))
  399. {
  400. removePos(iter, -1);
  401. changed = true;
  402. }
  403. }
  404. return changed;
  405. }
  406. public boolean retainAll(Collection<?> c)
  407. {
  408. boolean changed = false;
  409. for (int iter = startPos(); (iter = nextPos(iter)) != 0; )
  410. {
  411. Object value = getPosPrevious(iter);
  412. if (! c.contains(value))
  413. {
  414. removePos(iter, -1);
  415. changed = true;
  416. }
  417. }
  418. return changed;
  419. }
  420. public void clear()
  421. {
  422. removePos(startPos(), endPos());
  423. }
  424. /** Tests whether the position has the "isAfter" property.
  425. * I.e. if something is inserted at the position, will
  426. * the iterator end up being after the new data? */
  427. protected boolean isAfterPos (int ipos)
  428. {
  429. return (ipos & 1) != 0;
  430. }
  431. /** Generate a position at a given index.
  432. * The result is a position cookie that must be free'd with releasePos.
  433. * @param index offset from beginning of desired position
  434. * @param isAfter should the position have the isAfter property
  435. * @exception IndexOutOfBoundsException if index is out of bounds
  436. */
  437. public int createPos (int index, boolean isAfter) {
  438. return (index << 1) | (isAfter ? 1 : 0);
  439. }
  440. public int createRelativePos(int pos, int delta, boolean isAfter)
  441. {
  442. return createPos(nextIndex(pos) + delta, isAfter);
  443. }
  444. public int startPos () { return 0; }
  445. public int endPos () { return -1; }
  446. /**
  447. * Reclaim any resources used by the given position int.
  448. * @param ipos the Pos being free'd.
  449. */
  450. protected void releasePos(int ipos)
  451. {
  452. }
  453. /** Make a copy of a position int.
  454. * For simple positions returns the argument.
  455. * However, if the positions are magic cookies that are actively managed
  456. * by the sequence (as opposed to for example a simple index), then making
  457. * a copy may need to increment a reference count, or maybe allocate a
  458. * new position cookie. In any case, the new position is initialized to
  459. * the same offset (and isAfter property) as the original.
  460. * @param ipos the position being copied.
  461. * @return the new position
  462. */
  463. public int copyPos (int ipos)
  464. {
  465. return ipos;
  466. }
  467. /** Get offset of (ipos1) relative to (ipos0). */
  468. protected int getIndexDifference(int ipos1, int ipos0)
  469. {
  470. return nextIndex(ipos1) - nextIndex(ipos0);
  471. }
  472. /**
  473. * Get the offset from the beginning corresponding to a position cookie.
  474. */
  475. protected int nextIndex(int ipos) {
  476. return ipos == -1 ? size() : ipos >>> 1;
  477. }
  478. protected int fromEndIndex(int ipos)
  479. {
  480. return size() - nextIndex(ipos);
  481. }
  482. /**
  483. * Get the size of the (sub-) sequence containing a given position.
  484. * Normally the same as size(), but may be different if this Sequence
  485. * is a tree and the position points at an interior node.
  486. */
  487. protected int getContainingSequenceSize(int ipos)
  488. {
  489. return size();
  490. }
  491. public boolean hasNext (int ipos)
  492. {
  493. return nextIndex(ipos) != size();
  494. }
  495. public int getNextKind(int ipos)
  496. {
  497. return hasNext(ipos) ? Sequence.OBJECT_VALUE : Sequence.EOF_VALUE;
  498. }
  499. public String getNextTypeName(int ipos)
  500. {
  501. Object type = getNextTypeObject(ipos);
  502. return type == null ? null : type.toString();
  503. }
  504. public E getNextTypeObject(int ipos)
  505. {
  506. return null;
  507. }
  508. /** Called by SeqPosition.hasPrevious. */
  509. protected boolean hasPrevious(int ipos)
  510. {
  511. return nextIndex(ipos) != 0;
  512. }
  513. /** Return the next position following the argument.
  514. * The new position has the isAfter property.
  515. * The argument is implicitly released (as in releasePos).
  516. * Returns 0 if we are already at end of file.
  517. */
  518. public int nextPos (int ipos)
  519. {
  520. if (! hasNext(ipos))
  521. return 0;
  522. int next = createRelativePos(ipos, 1, true);
  523. releasePos(ipos);
  524. return next;
  525. }
  526. /** Return the previous position following the argument.
  527. * The new position has the isBefore property.
  528. * The argument is implicitly released (as in releasePos).
  529. * Returns -1 if we are already at beginning of file.
  530. */
  531. public int previousPos (int ipos)
  532. {
  533. if (! hasPrevious(ipos))
  534. return 0;
  535. int next = createRelativePos(ipos, -1, false);
  536. releasePos(ipos);
  537. return next;
  538. }
  539. /** Set position before first child (of the element following position).
  540. * @return true if there is a child sequence (which might be empty);
  541. * false if current position is end of sequence or following element
  542. * is atomic (cannot have children).
  543. */
  544. public final boolean gotoChildrenStart(TreePosition pos)
  545. {
  546. int ipos = firstChildPos(pos.getPos());
  547. if (ipos == 0)
  548. return false;
  549. pos.push(this, ipos);
  550. return true;
  551. }
  552. /** Get position before first child (of the element following position).
  553. * @param ipos parent position. It is not released by this method.
  554. * @return non-zero position cookie if there is a child sequence
  555. * (which might be empty); zero if current position is end of sequence
  556. * or following element is atomic (cannot have children).
  557. */
  558. public int firstChildPos (int ipos)
  559. {
  560. return 0;
  561. }
  562. public int firstChildPos (int ipos, ItemPredicate predicate)
  563. {
  564. int child = firstChildPos(ipos);
  565. if (child == 0)
  566. return 0;
  567. if (predicate.isInstancePos(this, child))
  568. return child;
  569. else
  570. return nextMatching(child, predicate, endPos(), false);
  571. }
  572. /** Like firstChildPos.
  573. * Problem: Should this stop before we get to children?
  574. * I think so, but that requires changes to TreeList. */
  575. public int firstAttributePos (int ipos)
  576. {
  577. return 0;
  578. }
  579. /** Get position of parent.
  580. * @param ipos child position. It is not released by this method.
  581. * @return the p os of the parent, or endPos() is there is no known parent.
  582. */
  583. public int parentPos (int ipos)
  584. {
  585. return endPos();
  586. }
  587. protected boolean gotoParent(TreePosition pos)
  588. {
  589. if (pos.depth < 0)
  590. return false;
  591. pos.pop();
  592. return true;
  593. }
  594. public int getAttributeLength()
  595. {
  596. return 0;
  597. }
  598. public Object getAttribute(int index)
  599. {
  600. return null;
  601. }
  602. protected boolean gotoAttributesStart(TreePosition pos)
  603. {
  604. return false;
  605. }
  606. /** Get the element following the specified position.
  607. * @param ipos the specified position.
  608. * @return the following element, or eofValue if there is none.
  609. * Called by SeqPosition.getNext.
  610. * FIXME Should change eof handling so return type can be E.
  611. */
  612. public Object getPosNext(int ipos)
  613. {
  614. if (! hasNext(ipos))
  615. return Sequence.eofValue;
  616. return get(nextIndex(ipos));
  617. }
  618. /** Get the element before the specified position.
  619. * @param ipos the specified position.
  620. * @return the following element, or eofValue if there is none.
  621. * FIXME Should change eof handling so return type can be E.
  622. */
  623. public Object getPosPrevious(int ipos)
  624. {
  625. int index = nextIndex(ipos);
  626. if (index <= 0)
  627. return Sequence.eofValue;
  628. return get(index - 1);
  629. }
  630. protected void setPosNext(int ipos, E value)
  631. {
  632. int index = nextIndex(ipos);
  633. if (index >= size())
  634. throw new IndexOutOfBoundsException();
  635. set(index, value);
  636. }
  637. protected void setPosPrevious(int ipos, E value)
  638. {
  639. int index = nextIndex(ipos);
  640. if (index == 0)
  641. throw new IndexOutOfBoundsException();
  642. set(index - 1, value);
  643. }
  644. public final int nextIndex(SeqPosition pos)
  645. {
  646. return nextIndex(pos.ipos);
  647. }
  648. /** Compare two positions, and indicate if they are the same position. */
  649. public boolean equals(int ipos1, int ipos2)
  650. {
  651. return compare(ipos1, ipos2) == 0;
  652. }
  653. /** Compare two positions, and indicate their relative order. */
  654. public int compare(int ipos1, int ipos2)
  655. {
  656. int i1 = nextIndex(ipos1);
  657. int i2 = nextIndex(ipos2);
  658. return i1 < i2 ? -1 : i1 > i2 ? 1 : 0;
  659. }
  660. public final int compare(SeqPosition i1, SeqPosition i2)
  661. {
  662. return compare(i1.ipos, i2.ipos);
  663. }
  664. public Object[] toArray()
  665. {
  666. int len = size();
  667. Object[] arr = new Object[len];
  668. int it = startPos();
  669. int i = 0;
  670. while ((it = nextPos(it)) != 0)
  671. arr[i++] = getPosPrevious(it);
  672. return arr;
  673. }
  674. public <T> T[] toArray(T[] arr)
  675. {
  676. int alen = arr.length;
  677. int len = size();
  678. if (len > alen)
  679. {
  680. Class componentType = arr.getClass().getComponentType();
  681. arr = (T[]) java.lang.reflect.Array.newInstance(componentType, len);
  682. alen = len;
  683. }
  684. int it = startPos();
  685. for (int i = 0; (it = nextPos(it)) != 0; i++)
  686. {
  687. arr[i] = (T) getPosPrevious(it);
  688. }
  689. if (len < alen)
  690. arr[len] = null;
  691. return arr;
  692. }
  693. /** This is used for the XML concept of "document order". */
  694. public int stableCompare (AbstractSequence other)
  695. {
  696. int id1 = System.identityHashCode(this);
  697. int id2 = System.identityHashCode(other);
  698. return id1 < id2 ? -1 : id1 > id2 ? 1 : 0;
  699. }
  700. /** This is used for the XML concept of "document order".
  701. * It is overridden in gnu.xml.NodeTree for a more robust implementation.
  702. */
  703. public static int compare(AbstractSequence seq1, int pos1,
  704. AbstractSequence seq2, int pos2)
  705. {
  706. if (seq1 == seq2)
  707. return seq1.compare(pos1, pos2);
  708. return seq1.stableCompare(seq2);
  709. }
  710. public int hashCode()
  711. {
  712. if (rank() != 1 && this instanceof Array)
  713. return Arrays.hashCode((Array) this);
  714. // Implementation specified by the Collections specification.
  715. int hash = 1;
  716. for (int i = startPos(); (i = nextPos(i)) != 0; )
  717. {
  718. Object obj = getPosPrevious(i);
  719. hash = 31*hash + (obj==null ? 0 : obj.hashCode());
  720. }
  721. return hash;
  722. }
  723. public int boundedHash(int seed, int limit) {
  724. int count = 0;
  725. int sublimit = limit >> 1;
  726. for (int i = startPos(); (i = nextPos(i)) != 0; ) {
  727. if (++count > limit)
  728. break;
  729. int h = HashUtils.boundedHash(getPosPrevious(i), 0, sublimit);
  730. seed = HashUtils.murmur3step(seed, h);
  731. }
  732. return HashUtils.murmur3finish(seed, count);
  733. }
  734. public boolean equals(Object o)
  735. {
  736. // Compatible with the Collections specification.
  737. // FIXME should also depend on class?
  738. if (! (this instanceof java.util.List)
  739. || ! (o instanceof java.util.List))
  740. return this == o;
  741. Iterator<E> it1 = iterator();
  742. Iterator<E> it2 = ((java.util.List<E>) o).iterator();
  743. for (;;)
  744. {
  745. boolean more1 = it1.hasNext();
  746. boolean more2 = it2.hasNext();
  747. if (more1 != more2)
  748. return false;
  749. if (! more1)
  750. return true;
  751. E e1 = it1.next();
  752. E e2 = it2.next();
  753. if (e1 == null)
  754. {
  755. if (e2 != null)
  756. return false;
  757. }
  758. else if (! e1.equals(e2))
  759. return false;
  760. }
  761. }
  762. public Sequence subSequence(SeqPosition start, SeqPosition end)
  763. {
  764. return subSequencePos(start.ipos, end.ipos);
  765. }
  766. protected Sequence<E> subSequencePos(int ipos0, int ipos1)
  767. {
  768. return new SubSequence<E>(this, ipos0, ipos1);
  769. }
  770. public List<E> subList(int fromIx, int toIx)
  771. {
  772. return subSequencePos(createPos(fromIx, false),
  773. createPos(toIx, true));
  774. }
  775. /** Copy an element specified by a position pair to a Consumer.
  776. * @return if hasNext(ipos). */
  777. public boolean consumeNext (int ipos, Consumer out)
  778. {
  779. int next = nextPos(ipos);
  780. if (next == 0)
  781. return false;
  782. consumePosRange(ipos, next, out);
  783. return true;
  784. }
  785. public void consumePosRange(int iposStart, int iposEnd, Consumer out)
  786. {
  787. if (out.ignoring())
  788. return;
  789. int it = copyPos(iposStart);
  790. while (! equals(it, iposEnd))
  791. {
  792. if (! hasNext(it))
  793. throw new RuntimeException();
  794. out.writeObject(getPosNext(it));
  795. it = nextPos(it);
  796. }
  797. releasePos(it);
  798. }
  799. public void consume(int fromIndex, int toIndex, Consumer out) {
  800. int ipos0 = createPos(fromIndex, false);
  801. int ipos1 = createPos(toIndex, true);
  802. consumePosRange(ipos0, ipos1, out);
  803. releasePos(ipos0);
  804. releasePos(ipos1);
  805. }
  806. public void consume(Consumer out) {
  807. boolean isSequence =
  808. this instanceof Sequence && ! (this instanceof CharSequence);
  809. if (isSequence)
  810. out.startElement("#sequence");
  811. consumePosRange(startPos(), endPos(), out);
  812. if (isSequence)
  813. out.endElement();
  814. }
  815. public void toString (String sep, StringBuffer sbuf)
  816. {
  817. boolean seen = false;
  818. for (int i = startPos(); (i = nextPos(i)) != 0; )
  819. {
  820. if (seen)
  821. sbuf.append(sep);
  822. else
  823. seen = true;
  824. sbuf.append(getPosPrevious(i));
  825. }
  826. }
  827. public String toString ()
  828. {
  829. StringBuffer sbuf = new StringBuffer(100);
  830. if (this instanceof Sequence)
  831. sbuf.append('[');
  832. toString(", ", sbuf);
  833. if (this instanceof Sequence)
  834. sbuf.append(']');
  835. return sbuf.toString();
  836. }
  837. }