(**************************************************************************)
(* *)
(* Copyright (C) Jean-Christophe Filliatre *)
(* *)
(* This software is free software; you can redistribute it and/or *)
(* modify it under the terms of the GNU Library General Public *)
(* License version 2, with the special exception on linking *)
(* described in file LICENSE. *)
(* *)
(* This software is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *)
(* *)
(**************************************************************************)
(*s Knuth-Morris-Pratt implementation. The shift table is called [next] here
and stored in an array. *)
open Printf
let debug = ref false
let search p =
let m = String.length p in
let next = Array.create m 0 in
(* initialization of [next] *)
let i = ref 1 in
let j = ref 0 in
if m > 1 then begin
while !i < m - 1 do
if p.[!i] = p.[!j] then begin
i := !i + 1; j:= !j + 1; next.(!i) <- !j
end else
if !j = 0 then i := !i + 1 (* next[i] <- 0 *) else j := next.(!j)
done
end;
(* debug: dump of the [next] table *)
if !debug then
for i = 0 to m - 1 do eprintf "next[%d]=%d\n" i next.(i) done;
fun t ->
(* search in [t] *)
let n = String.length t in
i := 0;
j := 0;
while !j < m && !i < n do
if t.[!i] = p.[!j] then begin
i := !i + 1; j:= !j + 1
end else
if !j = 0 then i := !i + 1 else j := next.(!j)
done;
if !j = m then !i - m else raise Not_found
(*s Functorial interface. *)
module type STRING = sig
type t
type char
val length : t -> int
val get : t -> int -> char
end
module Make(P : STRING)(T : STRING with type char = P.char) = struct
let search p =
let m = P.length p in
let next = Array.create m 0 in
(* initialization of [next] *)
let i = ref 1 in
let j = ref 0 in
if m > 1 then begin
while !i < m - 1 do
if P.get p !i = P.get p !j then begin
i := !i + 1; j:= !j + 1; next.(!i) <- !j
end else
if !j = 0 then i := !i + 1 else j := next.(!j)
done
end;
fun t ->
(* search in [t] *)
let n = T.length t in
i := 0;
j := 0;
while !j < m && !i < n do
if T.get t !i = P.get p !j then begin
i := !i + 1; j:= !j + 1
end else
if !j = 0 then i := !i + 1 else j := next.(!j)
done;
if !j = m then !i - m else raise Not_found
end