index.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. const GOOD_LEAF_SIZE = 200
  2. // :: class<T> A rope sequence is a persistent sequence data structure
  3. // that supports appending, prepending, and slicing without doing a
  4. // full copy. It is represented as a mostly-balanced tree.
  5. class RopeSequence {
  6. // length:: number
  7. // The length of the rope.
  8. // :: (union<[T], RopeSequence<T>>) → RopeSequence<T>
  9. // Append an array or other rope to this one, returning a new rope.
  10. append(other) {
  11. if (!other.length) return this
  12. other = RopeSequence.from(other)
  13. return (!this.length && other) ||
  14. (other.length < GOOD_LEAF_SIZE && this.leafAppend(other)) ||
  15. (this.length < GOOD_LEAF_SIZE && other.leafPrepend(this)) ||
  16. this.appendInner(other)
  17. }
  18. // :: (union<[T], RopeSequence<T>>) → RopeSequence<T>
  19. // Prepend an array or other rope to this one, returning a new rope.
  20. prepend(other) {
  21. if (!other.length) return this
  22. return RopeSequence.from(other).append(this)
  23. }
  24. appendInner(other) {
  25. return new Append(this, other)
  26. }
  27. // :: (?number, ?number) → RopeSequence<T>
  28. // Create a rope repesenting a sub-sequence of this rope.
  29. slice(from = 0, to = this.length) {
  30. if (from >= to) return RopeSequence.empty
  31. return this.sliceInner(Math.max(0, from), Math.min(this.length, to))
  32. }
  33. // :: (number) → T
  34. // Retrieve the element at the given position from this rope.
  35. get(i) {
  36. if (i < 0 || i >= this.length) return undefined
  37. return this.getInner(i)
  38. }
  39. // :: ((element: T, index: number) → ?bool, ?number, ?number)
  40. // Call the given function for each element between the given
  41. // indices. This tends to be more efficient than looping over the
  42. // indices and calling `get`, because it doesn't have to descend the
  43. // tree for every element.
  44. forEach(f, from = 0, to = this.length) {
  45. if (from <= to)
  46. this.forEachInner(f, from, to, 0)
  47. else
  48. this.forEachInvertedInner(f, from, to, 0)
  49. }
  50. // :: ((element: T, index: number) → U, ?number, ?number) → [U]
  51. // Map the given functions over the elements of the rope, producing
  52. // a flat array.
  53. map(f, from = 0, to = this.length) {
  54. let result = []
  55. this.forEach((elt, i) => result.push(f(elt, i)), from, to)
  56. return result
  57. }
  58. // :: (?union<[T], RopeSequence<T>>) → RopeSequence<T>
  59. // Create a rope representing the given array, or return the rope
  60. // itself if a rope was given.
  61. static from(values) {
  62. if (values instanceof RopeSequence) return values
  63. return values && values.length ? new Leaf(values) : RopeSequence.empty
  64. }
  65. // flatten:: () → [T]
  66. // Return the content of this rope as an array.
  67. }
  68. class Leaf extends RopeSequence {
  69. constructor(values) {
  70. super()
  71. this.values = values
  72. }
  73. flatten() {
  74. return this.values
  75. }
  76. sliceInner(from, to) {
  77. if (from == 0 && to == this.length) return this
  78. return new Leaf(this.values.slice(from, to))
  79. }
  80. getInner(i) {
  81. return this.values[i]
  82. }
  83. forEachInner(f, from, to, start) {
  84. for (let i = from; i < to; i++)
  85. if (f(this.values[i], start + i) === false) return false
  86. }
  87. forEachInvertedInner(f, from, to, start) {
  88. for (let i = from - 1; i >= to; i--)
  89. if (f(this.values[i], start + i) === false) return false
  90. }
  91. leafAppend(other) {
  92. if (this.length + other.length <= GOOD_LEAF_SIZE)
  93. return new Leaf(this.values.concat(other.flatten()))
  94. }
  95. leafPrepend(other) {
  96. if (this.length + other.length <= GOOD_LEAF_SIZE)
  97. return new Leaf(other.flatten().concat(this.values))
  98. }
  99. get length() { return this.values.length }
  100. get depth() { return 0 }
  101. }
  102. // :: RopeSequence
  103. // The empty rope sequence.
  104. RopeSequence.empty = new Leaf([])
  105. class Append extends RopeSequence {
  106. constructor(left, right) {
  107. super()
  108. this.left = left
  109. this.right = right
  110. this.length = left.length + right.length
  111. this.depth = Math.max(left.depth, right.depth) + 1
  112. }
  113. flatten() {
  114. return this.left.flatten().concat(this.right.flatten())
  115. }
  116. getInner(i) {
  117. return i < this.left.length ? this.left.get(i) : this.right.get(i - this.left.length)
  118. }
  119. forEachInner(f, from, to, start) {
  120. let leftLen = this.left.length
  121. if (from < leftLen &&
  122. this.left.forEachInner(f, from, Math.min(to, leftLen), start) === false)
  123. return false
  124. if (to > leftLen &&
  125. this.right.forEachInner(f, Math.max(from - leftLen, 0), Math.min(this.length, to) - leftLen, start + leftLen) === false)
  126. return false
  127. }
  128. forEachInvertedInner(f, from, to, start) {
  129. let leftLen = this.left.length
  130. if (from > leftLen &&
  131. this.right.forEachInvertedInner(f, from - leftLen, Math.max(to, leftLen) - leftLen, start + leftLen) === false)
  132. return false
  133. if (to < leftLen &&
  134. this.left.forEachInvertedInner(f, Math.min(from, leftLen), to, start) === false)
  135. return false
  136. }
  137. sliceInner(from, to) {
  138. if (from == 0 && to == this.length) return this
  139. let leftLen = this.left.length
  140. if (to <= leftLen) return this.left.slice(from, to)
  141. if (from >= leftLen) return this.right.slice(from - leftLen, to - leftLen)
  142. return this.left.slice(from, leftLen).append(this.right.slice(0, to - leftLen))
  143. }
  144. leafAppend(other) {
  145. let inner = this.right.leafAppend(other)
  146. if (inner) return new Append(this.left, inner)
  147. }
  148. leafPrepend(other) {
  149. let inner = this.left.leafPrepend(other)
  150. if (inner) return new Append(inner, this.right)
  151. }
  152. appendInner(other) {
  153. if (this.left.depth >= Math.max(this.right.depth, other.depth) + 1)
  154. return new Append(this.left, new Append(this.right, other))
  155. return new Append(this, other)
  156. }
  157. }
  158. export default RopeSequence