add 'SearchList.exists' function to fcore/search-list.sml function, and make sure we check if mmatchedIdx exists before inserting or appending (so we maintain set-like semantics where each number exists only once)

This commit is contained in:
2024-11-24 21:38:58 +00:00
parent c6343cac40
commit d399016c1a
3 changed files with 120 additions and 44 deletions

View File

@@ -69,4 +69,28 @@ struct
fun equalOrMore (findNum, vec) =
helpBinSearch (findNum, vec, 0, Vector.length vec - 1)
end
local
fun helpExists (findNum, vec, low, high) =
let
val mid = low + ((high - low) div 2)
in
if high >= low then
let
val midVal = Vector.sub (vec, mid)
in
if midVal = findNum then
true
else if midVal < findNum then
helpExists (findNum, vec, mid + 1, high)
else
helpExists (findNum, vec, low, mid - 1)
end
else
false
end
in
fun exists (findNum, vec) =
helpExists (findNum, vec, 0, Vector.length vec - 1)
end
end

View File

@@ -5,8 +5,7 @@ struct
case tl of
tlhd :: tltl =>
helpNextMatch (0, tlhd, tltl, absIdx, searchString, matchedChrs)
| [] =>
NONE
| [] => NONE
else
let
val hdChr = String.sub (hd, idx)
@@ -14,13 +13,11 @@ struct
in
if hdChr = searchChr then
if matchedChrs + 1 = String.size searchString then
let
val matchedIdx = absIdx - String.size searchString + 1
in
SOME matchedIdx
let val matchedIdx = absIdx - String.size searchString + 1
in SOME matchedIdx
end
else
helpNextMatch
helpNextMatch
(idx + 1, hd, tl, absIdx + 1, searchString, matchedChrs + 1)
else
helpNextMatch (idx + 1, hd, tl, absIdx + 1, searchString, 0)
@@ -29,20 +26,18 @@ struct
fun nextMatch (bufferIdx, absIdx, rightStrings, searchString) =
case rightStrings of
hd :: tl =>
let
let
val strIdx = absIdx - bufferIdx
in
if strIdx < String.size hd then
helpNextMatch (strIdx, hd, tl, absIdx, searchString, 0)
else
(case tl of
tlhd :: tltl =>
let
val strIdx = strIdx - String.size hd
in
helpNextMatch (strIdx, tlhd, tltl, absIdx, searchString, 0)
end
| [] => NONE)
tlhd :: tltl =>
let val strIdx = strIdx - String.size hd
in helpNextMatch (strIdx, tlhd, tltl, absIdx, searchString, 0)
end
| [] => NONE)
end
| [] => NONE
@@ -53,12 +48,26 @@ struct
in
case nextMatch (bufferIdx, absIdx, rightStrings, searchString) of
SOME matchedIdx =>
let
val searchList = SearchList.append (matchedIdx, searchList)
in
(* Edge case: we may be searching for a string like "a"
* when the buffer represents "aaa aaa aaa".
* In this case, there will be continual matches that are consecutive
* and we need to check every char in the buffer which is absIdx + 1.
* However, we can skip to matchedIdx + 1 if matchedIdx already exists
* in the searchList because we know the string between
* [absIdx ... matchedIdx - 1] contains no matches.
* This check is important to preserve the set-like semaantics
* of the searchList too: SearchList.append does not check for this.
* *)
if SearchList.exists (matchedIdx, searchList) then
helpFromStart
(app, origIdx, matchedIdx + 1, buffer, searchString, searchList)
end
else
let
val searchList = SearchList.append (matchedIdx, searchList)
in
helpFromStart
(app, origIdx, absIdx + 1, buffer, searchString, searchList)
end
| NONE =>
let
val buffer = LineGap.goToIdx (origIdx, buffer)
@@ -80,38 +89,46 @@ struct
app
(* searches for matchedIdx within a range from the buffer instead of from start *)
fun helpFromRange
fun helpFromRange
(origIdx, curIdx, finishIdx, buffer, searchString, searchList) =
let
val buffer = LineGap.goToIdx (curIdx, buffer)
val {idx = bufferIdx, rightStrings, ...} = buffer
in
case nextMatch (bufferIdx, curIdx, rightStrings, searchString) of
SOME matchedIdx =>
if matchedIdx > finishIdx then
let
val buffer = LineGap.goToIdx (origIdx, buffer)
val searchList = SearchList.goToNum (origIdx, searchList)
in
(buffer, searchList)
end
else
let
val searchList = SearchList.insert (matchedIdx, searchList)
in
helpFromRange
( origIdx, matchedIdx + 1, finishIdx
, buffer, searchString, searchList
)
end
| NONE =>
let
val buffer = LineGap.goToIdx (curIdx, buffer)
val {idx = bufferIdx, rightStrings, ...} = buffer
in
case nextMatch (bufferIdx, curIdx, rightStrings, searchString) of
SOME matchedIdx =>
if matchedIdx > finishIdx then
let
val buffer = LineGap.goToIdx (origIdx, buffer)
val searchList = SearchList.goToNum (origIdx, searchList)
in
(buffer, searchList)
end
end
else
let
val searchList =
if SearchList.exists (matchedIdx, searchList) then
searchList
else
SearchList.insert (matchedIdx, searchList)
in
helpFromRange
( origIdx
, curIdx + 1
, finishIdx
, buffer
, searchString
, searchList
)
end
| NONE =>
let
val buffer = LineGap.goToIdx (origIdx, buffer)
val searchList = SearchList.goToNum (origIdx, searchList)
in
(buffer, searchList)
end
end
fun fromRange (startIdx, length, buffer, searchString, searchList) =
let

View File

@@ -3,6 +3,7 @@ sig
type t = {left: int vector list, right: int vector list}
val empty: t
val exists: int * t -> bool
val insert: int * t -> t
val append: int * t -> t
val delete: int * int * string * t -> t
@@ -587,4 +588,38 @@ struct
in
moveRightAndMap (num, mapBy, left, right)
end
fun helpExistsRight (num, right) =
case right of
hd :: tl =>
let
val rlast = Vector.sub (hd, Vector.length hd - 1)
in
if num > rlast then helpExistsRight (num, tl)
else BinSearch.exists (num, hd)
end
| [] => false
fun helpExistsLeft (num, left) =
case left of
hd :: tl =>
let
val lfirst = Vector.sub (hd, 0)
in
if num < lfirst then helpExistsLeft (num, tl)
else BinSearch.exists (num, hd)
end
| [] => false
fun exists (num, {left, right}) =
case right of
rhd :: rtl =>
let
val rfirst = Vector.sub (rhd, 0)
in
if num = rfirst then true
else if num > rfirst then helpExistsRight (num, right)
else helpExistsLeft (num, left)
end
| [] => helpExistsLeft (num, left)
end