SortedNodes.java 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. // Copyright (c) 2003, 2008 Per M.A. Bothner.
  2. // This is free software; for terms and warranty disclaimer see ./COPYING.
  3. package gnu.kawa.xml;
  4. import gnu.lists.*;
  5. import gnu.xml.*;
  6. /** Manages a sequence of node references in document order without duplicates.
  7. * The most recently added element is just before the gap.
  8. * Optimized for the data being in order, or at least having good
  9. * locality (a node being "near" the previously-entered node).
  10. */
  11. public class SortedNodes extends Nodes {
  12. private int compareIndex(int index, AbstractSequence seq2, int ipos2) {
  13. AbstractSequence seq1 = vector.getSeq(index);
  14. int ipos1 = vector.getPos(index);
  15. return AbstractSequence.compare(seq1, ipos1, seq2, ipos2);
  16. }
  17. /** Find index where to put position (seq, ipos).
  18. * Require {@code index>=start && index<end},
  19. * where {@code end==start+count}.
  20. * Require all position before index are "less than" (seq, ipos),
  21. * and all positions after are "greater than" (seq, ipos).
  22. * If there is no such index (because it is "same as"), return -1.
  23. */
  24. private int find (int start, int count, AbstractSequence seq, int ipos) {
  25. int lo = 0;
  26. int hi = count;
  27. // We use binary search, though the arraycopy operations in
  28. // writePosition limit the benefit - a sequence of writePosition
  29. // calls is still quadratic in the worst case
  30. // (but linear if locality is good).
  31. while (lo < hi) {
  32. int mid = (lo + hi) >>> 1;
  33. int cmp = compareIndex(start + mid, seq, ipos);
  34. if (cmp == 0)
  35. return -1;
  36. if (cmp > 0)
  37. hi = mid;
  38. else
  39. lo = mid + 1;
  40. }
  41. return start + lo;
  42. }
  43. int find(AbstractSequence seq, int ipos) {
  44. int count = size();
  45. if (count <= 0)
  46. return 0;
  47. // Optimize for the already sorted case, or secondarily for good
  48. // locality. So use the gapStart as the initial "mid-point".
  49. int lastIndex = vector.getLastIndex();
  50. int cmp = lastIndex < 0 ? -1 : compareIndex(lastIndex, seq, ipos);
  51. if (cmp < 0) {
  52. // The new node is after all nodes up to gapStart.
  53. int i = lastIndex+1;
  54. // Note that if the incoming nodes are already sorted (a
  55. // common case in path expressions), then find will
  56. // immediately return i.
  57. return find (i, count-i, seq, ipos);
  58. } else if (cmp == 0)
  59. return -1;
  60. else {
  61. return find (0, lastIndex, seq, ipos);
  62. }
  63. }
  64. @Override
  65. public void writePosition(SeqPosition position) {
  66. AbstractSequence seq = position.sequence;
  67. int ipos = position.ipos;
  68. int i = find(seq, ipos);
  69. if (i >= 0)
  70. vector.add(i, position);
  71. }
  72. @Override
  73. public void writePosition(AbstractSequence seq, int ipos) {
  74. int i = find(seq, ipos);
  75. if (i >= 0) {
  76. vector.add(i, (SeqPosition) null);
  77. vector.setBuffer(i, seq, ipos);
  78. }
  79. }
  80. }