diff --git a/README.md b/README.md index b571242..6e4ed7e 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ # Brolib-sml +## Introduction + Standard ML port of [this](https://github.com/hummy123/brolib) rope implementation. + +## Usage diff --git a/rope.sml b/rope.sml index 015203c..dbcc714 100644 --- a/rope.sml +++ b/rope.sml @@ -22,7 +22,24 @@ sig * because then line metadata will become invalid. *) val delete: int * int * t -> t - (* This below function verifies that line metadata is as expected, + (* Folds over the characters in the rope starting from the index + * in the second parameter. *) + val foldFromIdx: (char * 'a -> 'a) * int * t * 'a -> 'a + + (* Like the foldFromIdx function, but accepts a predicate as the second + * argument. + * If the predicate returns true, terminates and returns the result; + * else, continues folding until predicate returns true or until remaining + * characters have been traversed. *) + val foldFromIdxTerm: (char * 'a -> 'a) * ('a -> bool) * int * t * 'a -> 'a + + (* This function folds over the characters in the rope, + * starting from a given line number. + * The second argument is a predicate indicating when to stop folding. *) + val foldLines: (char * 'a -> 'a) * ('a -> bool) * int * t * 'a -> 'a + + (* This below function is just for testing. + * It verifies that line metadata is as expected, * raising an exception if it is different, * and returning true if it is the same. *) val verifyLines: t -> bool @@ -666,6 +683,78 @@ struct in if didIns then insRoot rope else rope end + fun foldStringChars (apply, term, pos, str, strSize, acc) = + if pos < strSize then + if term acc then + acc + else + let + val chr = String.sub (str, pos) + val acc = apply (chr, acc) + in + foldStringChars (apply, term, pos + 1, str, strSize, acc) + end + else + acc + + fun foldFromIdxTerm (apply, term, idx, rope, acc) = + case rope of + N2 (l, lm, _, r) => + if idx < lm then + let + val acc = foldFromIdxTerm (apply, term, idx, l, acc) + in + if term acc then acc + else foldFromIdxTerm (apply, term, idx - lm, r, acc) + end + else + foldFromIdxTerm (apply, term, idx - lm, r, acc) + | N1 t => foldFromIdxTerm (apply, term, idx, t, acc) + | N0 (str, _) => + foldStringChars (apply, term, idx, str, String.size str, acc) + | _ => raise AuxConstructor + + fun noTerm _ = false + + fun foldFromIdx (apply, idx, rope, acc) = + foldFromIdxTerm (apply, noTerm, idx, rope, acc) + + fun foldLineCharsTerm (apply, term, pos, str, strSize, acc) = + if pos < strSize then + case term acc of + false => + let + val chr = String.sub (str, pos) + val acc = apply (chr, acc) + in + foldLineCharsTerm (apply, term, pos, str, strSize, acc) + end + | true => acc + else + acc + + fun foldLines (apply, term, lineNum, rope, acc) = + case rope of + N2 (l, _, lmv, r) => + if lineNum < lmv then + let + val acc = foldLines (apply, term, lineNum, rope, acc) + in + if term acc then acc + else foldLines (apply, term, lineNum - lmv, r, acc) + end + else + foldLines (apply, term, lineNum - lmv, r, acc) + | N1 t => foldLines (apply, term, lineNum, t, acc) + | N0 (str, vec) => + let + val idx = + if Vector.length vec > 0 then Vector.sub (vec, lineNum) else 0 + in + foldLineCharsTerm (apply, term, idx, str, String.size str, acc) + end + | _ => raise AuxConstructor + fun verifyLines rope = foldr ( (fn (_, str, vec) => diff --git a/tiny_rope.sml b/tiny_rope.sml index 18ab7e1..c82cac3 100644 --- a/tiny_rope.sml +++ b/tiny_rope.sml @@ -8,6 +8,8 @@ sig val append: string * t -> t val delete: int * int * t -> t val toString: t -> string + val foldFromIdxTerm: (char * 'a -> 'a) * ('a -> bool) * int * t * 'a -> 'a + val foldFromIdx: (char * 'a -> 'a) * int * t * 'a -> 'a end structure TinyRope :> TINY_ROPE = @@ -21,8 +23,6 @@ struct exception AuxConstructor - exception Substring of int - fun foldr (f, state, rope) = case rope of N2 (l, _, r) => @@ -350,4 +350,39 @@ struct let val (rope, didAdd) = del (start, start + length, rope) in if didAdd then insRoot rope else delRoot rope end + + fun foldStringChars (apply, term, pos, str, strSize, acc) = + if pos < strSize then + case term acc of + false => + let + val chr = String.sub (str, pos) + val acc = apply (chr, acc) + in + foldStringChars (apply, term, pos + 1, str, strSize, acc) + end + | true => acc + else + acc + + fun foldFromIdxTerm (apply, term, idx, rope, acc) = + case rope of + N2 (l, lm, r) => + if idx < lm then + let + val acc = foldFromIdxTerm (apply, term, idx, l, acc) + in + if term acc then acc + else foldFromIdxTerm (apply, term, idx - lm, r, acc) + end + else + foldFromIdxTerm (apply, term, idx - lm, r, acc) + | N1 t => foldFromIdxTerm (apply, term, idx, t, acc) + | N0 str => foldStringChars (apply, term, idx, str, String.size str, acc) + | _ => raise AuxConstructor + + fun noTerm _ = false + + fun foldFromIdx (apply, idx, rope, acc) = + foldFromIdxTerm (apply, noTerm, idx, rope, acc) end