diff --git a/shf/fcore/search-list/persistent-vector.sml b/shf/fcore/search-list/persistent-vector.sml index c246e71..106fd58 100644 --- a/shf/fcore/search-list/persistent-vector.sml +++ b/shf/fcore/search-list/persistent-vector.sml @@ -7,14 +7,14 @@ struct * *) datatype t = BRANCH of t vector * int vector - | LEAF of {start: int, finish: int} vector * int vector + | LEAF of int vector * int vector val maxSize = 32 val halfSize = 16 fun isEmpty t = case t of - LEAF (_, sizes) => Vector.length sizes = 0 + LEAF (_, endSizes) => Vector.length endSizes = 0 | BRANCH (_, sizes) => Vector.length sizes = 0 val empty = LEAF (#[], #[]) @@ -38,15 +38,16 @@ struct isInRange (nextCheckIdx, Vector.sub (nodes, searchIdx)) end end - | LEAF (values, sizes) => + | LEAF (startSizes, endSizes) => let - val searchIdx = BinSearch.equalOrMore (checkIdx, sizes) + val searchIdx = BinSearch.equalOrMore (checkIdx, endSizes) in if searchIdx = ~1 then false else let - val {start, finish} = Vector.sub (values, searchIdx) + val start = Vector.sub (startSizes, searchIdx) + val finish = Vector.sub (endSizes, searchIdx) in checkIdx >= start andalso checkIdx <= finish end @@ -55,16 +56,16 @@ struct fun getFinishIdx t = case t of BRANCH (_, sizes) => Vector.sub (sizes, Vector.length sizes - 1) - | LEAF (_, sizes) => Vector.sub (sizes, Vector.length sizes - 1) + | LEAF (_, endSizes) => Vector.sub (endSizes, Vector.length endSizes - 1) fun getStartIdx t = case t of BRANCH (nodes, _) => getStartIdx (Vector.sub (nodes, 0)) - | LEAF (items, _) => - if Vector.length items = 0 then + | LEAF (startSizes, _) => + if Vector.length startSizes = 0 then 0 else - #start (Vector.sub (items, 0)) + Vector.sub (startSizes, 0) fun helpAppend (start, finish, tree) = case tree of @@ -106,26 +107,25 @@ struct UPDATE newNodes end end - | LEAF (values, sizes) => - if Vector.length values + 1 > maxSize then + | LEAF (startSizes, endSizes) => + if Vector.length endSizes + 1 > maxSize then (* when we split a leaf into two vectors, * we want to adjust the start and finish parameters * so that they don't contain the offset relevant to the * "lower" vector, which was split from *) let - val prevFinish = Vector.sub (sizes, Vector.length sizes - 1) + val prevFinish = Vector.sub (endSizes, Vector.length endSizes - 1) val start = start - prevFinish val finish = finish - prevFinish - val newNode = LEAF (#[{start = start, finish = finish}], #[finish]) + val newNode = LEAF (#[start], #[finish]) in APPEND newNode end else let - val newNode = Vector.concat - [values, #[{start = start, finish = finish}]] - val newSizes = Vector.concat [sizes, #[finish]] - val newNode = LEAF (newNode, newSizes) + val newStartSizes = Vector.concat [startSizes, #[start]] + val newEndSizes = Vector.concat [endSizes, #[finish]] + val newNode = LEAF (newStartSizes, newEndSizes) in UPDATE newNode end @@ -142,19 +142,21 @@ struct fun getStart tree = case tree of - LEAF (values, _) => Vector.sub (values, 0) + LEAF (startSizes, endSizes) => + {start = Vector.sub (startSizes, 0), finish = Vector.sub (endSizes, 0)} | BRANCH (nodes, _) => getStart (Vector.sub (nodes, 0)) fun helpNextMatch (cursorIdx, tree, absOffset) = case tree of - LEAF (values, sizes) => + LEAF (startSizes, endSizes) => let - val idx = BinSearch.equalOrMore (cursorIdx, sizes) + val idx = BinSearch.equalOrMore (cursorIdx, endSizes) in if idx = ~1 then {start = ~1, finish = ~1} else let - val {start, finish} = Vector.sub (values, idx) + val start = Vector.sub (startSizes, idx) + val finish = Vector.sub (endSizes, idx) in {start = start + absOffset, finish = finish + absOffset} end @@ -211,9 +213,10 @@ struct fun getLast (tree, absOffset) = case tree of - LEAF (values, _) => + LEAF (startSizes, endSizes) => let - val {start, finish} = Vector.sub (values, Vector.length values - 1) + val start = Vector.sub (startSizes, Vector.length startSizes - 1) + val finish = Vector.sub (endSizes, Vector.length endSizes - 1) in {start = start + absOffset, finish = finish + absOffset} end @@ -246,15 +249,16 @@ struct * or the caller to `helpPrevMatch` will. *) fun helpPrevMatch (cursorIdx, tree, absOffset) = case tree of - LEAF (values, sizes) => + LEAF (startSizes, endSizes) => let - val idx = BinSearch.equalOrMore (cursorIdx, sizes) + val idx = BinSearch.equalOrMore (cursorIdx, endSizes) in if idx < 0 then {start = ~1, finish = ~1} else if idx = 0 then let - val {start, finish} = Vector.sub (values, 0) + val start = Vector.sub (startSizes, 0) + val finish = Vector.sub (endSizes, 0) in if start < cursorIdx then {start = start + absOffset, finish = finish + absOffset} @@ -263,13 +267,15 @@ struct end else let - val {start, finish} = Vector.sub (values, idx) + val start = Vector.sub (startSizes, idx) + val finish = Vector.sub (endSizes, idx) in if cursorIdx > start then {start = start + absOffset, finish = finish + absOffset} else let - val {start, finish} = Vector.sub (values, idx - 1) + val start = Vector.sub (startSizes, idx - 1) + val finish = Vector.sub (endSizes, idx - 1) in {start = start + absOffset, finish = finish + absOffset} end @@ -339,37 +345,37 @@ struct fun splitLeft (splitIdx, tree) = case tree of - LEAF (items, sizes) => - if Vector.length items = 0 then + LEAF (startSizes, endSizes) => + if Vector.length startSizes = 0 then (* if tree is empty, then just return tree *) tree else let - val {start, ...} = Vector.sub (items, 0) + val start = Vector.sub (startSizes, 0) in - (* if all items are after splitIdx, + (* if all intervals are after splitIdx, * then we want to return an empty tree, * splitting everything *) if splitIdx < start then empty - else if splitIdx > Vector.sub (sizes, Vector.length sizes - 1) then - (* if all items are before splitIdx, + else if splitIdx > Vector.sub (endSizes, Vector.length endSizes - 1) then + (* if all intervals are before splitIdx, * then we want to return the same tree, * splitting nothing *) tree else (* we want to split from somewhere in middle, keeping left *) let - val idx = BinSearch.equalOrMore (splitIdx, sizes) + val idx = BinSearch.equalOrMore (splitIdx, endSizes) val idx = SOME idx - val items = VectorSlice.slice (items, 0, idx) - val items = VectorSlice.vector items + val startSizes = VectorSlice.slice (startSizes, 0, idx) + val startSizes = VectorSlice.vector startSizes - val sizes = VectorSlice.slice (sizes, 0, idx) - val sizes = VectorSlice.vector sizes + val endSizes = VectorSlice.slice (endSizes, 0, idx) + val endSizes = VectorSlice.vector endSizes in - LEAF (items, sizes) + LEAF (startSizes, endSizes) end end | BRANCH (nodes, sizes) => @@ -477,43 +483,42 @@ struct BRANCH (nodes, sizes) end end - | LEAF (items, sizes) => - if Vector.length items = 0 then + | LEAF (startSizes, endSizes) => + if Vector.length endSizes = 0 then tree else - if splitIdx > Vector.sub (sizes, Vector.length sizes - 1) then + if splitIdx > Vector.sub (endSizes, Vector.length endSizes - 1) then empty - else if splitIdx < #start (Vector.sub (items, 0)) then + else if splitIdx < Vector.sub (startSizes, 0) then tree else let - val idx = BinSearch.equalOrMore (splitIdx, sizes) - val {start, finish} = Vector.sub (items, idx) + val idx = BinSearch.equalOrMore (splitIdx, endSizes) + val start = Vector.sub (startSizes, idx) + val finish = Vector.sub (endSizes, idx) val idx = if splitIdx >= start then idx + 1 else idx in - if idx >= Vector.length items then + if idx >= Vector.length endSizes then empty else let val prevSize = if idx > 0 then - Vector.sub (sizes, idx - 1) + Vector.sub (endSizes, idx - 1) else 0 - val len = Vector.length items - idx - val itemsSlice = VectorSlice.slice (items, idx, SOME len) - val items = VectorSlice.map - (fn {start, finish} => - {start = start - prevSize, finish = finish - prevSize} - ) - itemsSlice - val sizes = Vector.map #finish items + val len = Vector.length startSizes - idx + val startSlice = VectorSlice.slice (startSizes, idx, SOME len) + val startSizes = VectorSlice.map (fn i => i - prevSize) startSlice + + val endSlice = VectorSlice.slice (endSizes, idx, SOME len) + val endSizes = VectorSlice.map (fn i => i - prevSize) endSlice in - LEAF (items, sizes) + LEAF (startSizes, endSizes) end end @@ -527,15 +532,12 @@ struct in BRANCH (nodes, sizes) end - | LEAF (items, sizes) => + | LEAF (startSizes, endSizes) => let - val items = Vector.map - (fn {start, finish} => - {start = start - decBy, finish = finish - decBy} - ) items - val sizes = Vector.map #finish items + val startSizes = Vector.map (fn i => i - decBy) startSizes + val endSizes = Vector.map (fn i => i - decBy) endSizes in - LEAF (items, sizes) + LEAF (startSizes, endSizes) end fun incrementBy (incBy, tree) = @@ -548,15 +550,12 @@ struct in BRANCH (nodes, sizes) end - | LEAF (items, sizes) => + | LEAF (startSizes, endSizes) => let - val items = Vector.map - (fn {start, finish} => - {start = start + incBy, finish = finish + incBy} - ) items - val sizes = Vector.map #finish items + val startSizes = Vector.map (fn i => i + incBy) startSizes + val endSizes = Vector.map (fn i => i + incBy) endSizes in - LEAF (items, sizes) + LEAF (startSizes, endSizes) end fun countDepthLoop (counter, tree) = @@ -572,26 +571,25 @@ struct fun mergeSameDepth (left, right) = case (left, right) of - (LEAF (leftItems, leftSizes), LEAF (rightItems, rightSizes)) => - if Vector.length leftItems + Vector.length rightItems <= maxSize then + (LEAF (leftStartSizes, leftEndSizes), LEAF (rightStartSizes, rightEndSizes)) => + if Vector.length leftStartSizes + Vector.length rightStartSizes <= maxSize then let - val offset = Vector.sub (leftSizes, Vector.length leftSizes - 1) - val newVecLen = Vector.length leftItems + Vector.length rightItems - val items = Vector.tabulate (newVecLen, + val offset = Vector.sub (leftEndSizes, Vector.length leftEndSizes - 1) + val newVecLen = Vector.length leftStartSizes + Vector.length rightStartSizes + val startSizes = Vector.tabulate (newVecLen, fn i => - if i < Vector.length leftItems then - Vector.sub (leftItems, i) + if i < Vector.length leftStartSizes then + Vector.sub (leftStartSizes, i) else - let - val {start, finish} = - Vector.sub (rightItems, i - Vector.length leftItems) - in - {start = start + offset, finish = finish + offset} - end - ) - val sizes = Vector.map #finish items + Vector.sub (rightStartSizes, i - Vector.length leftStartSizes) + offset) + val endSizes = Vector.tabulate (newVecLen, + fn i => + if i < Vector.length leftEndSizes then + Vector.sub (leftEndSizes, i) + else + Vector.sub (rightEndSizes, i - Vector.length leftEndSizes) + offset) in - MERGE_SAME_DEPTH_UPDATE (LEAF (items, sizes)) + MERGE_SAME_DEPTH_UPDATE (LEAF (startSizes, endSizes)) end else MERGE_SAME_DEPTH_FULL @@ -907,14 +905,15 @@ struct in branchLoop (0, acc) end - | LEAF (items, _) => + | LEAF (startSizes, endSizes) => let fun itemLoop (pos, acc, offset) = - if pos = Vector.length items then + if pos = Vector.length startSizes then acc else let - val {start, finish} = Vector.sub (items, pos) + val start = Vector.sub (startSizes, pos) + val finish = Vector.sub (endSizes, pos) val item = {start = start + offset, finish = finish + offset} in itemLoop (pos + 1, item :: acc, offset) diff --git a/shf/todo.md b/shf/todo.md index 19a4afb..86dc02f 100644 --- a/shf/todo.md +++ b/shf/todo.md @@ -1,5 +1,4 @@ # To-do list -- Refactor PersistentVector so that the LEAF node only contains integer vectors (one for the finishIdx, which we already have, and one for the startIdx) - Add tests for indent, dedent and remove-line-break motions - Add tests that searchList updates as expected too - Add tests for other yank motoins