(* * Index module based on tables. * An index is essentially a multi-level table. * Each entry has an associated data item and subtable. * * ---------------------------------------------------------------- * * Copyright (C) 2002 Michael Maire, Caltech * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, * version 2.1 of the License. * * This library 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. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Additional permission is given to link this library with the * OpenSSL project's "OpenSSL" library, and with the OCaml runtime, * and you may distribute the linked executables. See the file * LICENSE.libmojave for more details. * * Author: Michael Maire * mmaire@caltech.edu * * ---------------------------------------------------------------- * Revision History * * 2002 Apr 20 Michael Maire Initial Version * 2002 Apr 25 Michael Maire Renamed iter, maps, folds to *_all * added single level iters, maps, folds * 2002 Apr 26 Michael Maire Added functions for explicitly adding * subindices * 2002 May 1 Michael Maire Made all adds nondestructive towards * subindices (if subindex is not explicitly * specified in the add) * Changed interface *) (* * Elements. * This type specifies the type of the keys used in the index. *) module type OrderedType = sig type t val compare : t -> t -> int end (* * These are the functions provided by the index. *) module type LmIndex = sig (* index maps key lists to elements of type 'a *) type key type 'a t (* empty index and empty test *) val empty : 'a t val is_empty : 'a t -> bool (* tests/lookups - single level*) val mem : 'a t -> key -> bool val find : 'a t -> key -> 'a t * 'a val find_index : 'a t -> key -> 'a t val find_data : 'a t -> key -> 'a (* tests/lookups - multi level*) val mem_list : 'a t -> key list -> bool val find_list : 'a t -> key list -> 'a t * 'a val find_list_index : 'a t -> key list -> 'a t val find_list_data : 'a t -> key list -> 'a (* addition and removal - single level*) val add : 'a t -> key -> 'a -> 'a t val add_i : 'a t -> key -> 'a t * 'a -> 'a t val remove : 'a t -> key -> 'a t (* addition of a chain of nested entries *) val add_list : 'a t -> key list -> 'a list -> 'a t val add_list_i : 'a t -> key list -> ('a t * 'a) list -> 'a t (* addition/removal of single entries *) val add_entry : 'a t -> key list -> 'a -> 'a t val add_entry_i : 'a t -> key list -> 'a t * 'a -> 'a t val remove_entry : 'a t -> key list -> 'a t (* filter addition/removal - single level *) val filter_add : 'a t -> key -> ('a option -> 'a) -> 'a t val filter_add_i : 'a t -> key -> (('a t * 'a) option -> ('a t * 'a)) -> 'a t val filter_remove : 'a t -> key -> ('a -> 'a option) -> 'a t val filter_remove_i : 'a t -> key -> (('a t * 'a) -> ('a t * 'a) option) -> 'a t (* filter addition of a chain of nested entries *) val filter_add_list : 'a t -> key list -> ('a option -> 'a) list -> 'a t val filter_add_list_i : 'a t -> key list -> (('a t * 'a) option -> ('a t * 'a)) list -> 'a t (* filter addition/removal of single entries *) val filter_add_entry : 'a t -> key list -> ('a option -> 'a) -> 'a t val filter_add_entry_i : 'a t -> key list -> (('a t * 'a) option -> ('a t * 'a)) -> 'a t val filter_remove_entry : 'a t -> key list -> ('a -> 'a option) -> 'a t val filter_remove_entry_i : 'a t -> key list -> (('a t * 'a) -> ('a t * 'a) option) -> 'a t (* iterators, maps, and folds - single level *) val iter : (key -> ('a t * 'a) -> unit) -> 'a t -> unit val map : (('a t * 'a) -> ('b t * 'b)) -> 'a t -> 'b t val mapi : (key -> ('a t * 'a) -> ('b t * 'b)) -> 'a t -> 'b t val fold : ('a -> key -> ('b t * 'b) -> 'a) -> 'a -> 'b t -> 'a val fold_map : ('a -> key -> ('b t * 'b) -> 'a * ('c t * 'c)) -> 'a -> 'b t -> 'a * 'c t (* iterators, maps, and folds - entire index *) val iter_all : (key list -> 'a -> unit) -> 'a t -> unit val map_all : ('a -> 'b) -> 'a t -> 'b t val mapi_all : (key list -> 'a -> 'b) -> 'a t -> 'b t val fold_all : ('a -> key list -> 'b -> 'a) -> 'a -> 'b t -> 'a val fold_map_all : ('a -> key list -> 'b -> 'a * 'c) -> 'a -> 'b t -> 'a * 'c t end (* * Make the index. *) module LmMake (Base : OrderedType) : LmIndex with type key = Base.t = struct (* * Construct table type for elements. *) module EltTable = Lm_map.LmMake (Base) (* * An index is a tree of nested tables. *) type ('elt, 'data) tree = Leaf | Index of (('elt, 'data) tree * 'data) EltTable.t type key = Base.t type 'a t = (key, 'a) tree (* * An empty index is a leaf. *) let empty = Leaf (* * Test if index is empty. *) let is_empty = function Leaf -> true | Index _ -> false (* * Test membership of a key in an index. *) let mem index key = match index with Leaf -> false | Index table -> EltTable.mem table key (* * Lookup a key in an index. *) let find index key = match index with Leaf -> raise Not_found | Index table -> EltTable.find table key (* * Lookup the subindex for a key in an index. *) let find_index index key = let index, _ = find index key in index (* * Lookup the data for a key in an index. *) let find_data index key = let _, data = find index key in data (* * Test for membership of a key sequence in an index. *) let rec mem_list index keys = match keys with [] -> false | key :: [] -> mem index key | key :: keys -> let index = find_index index key in mem_list index keys (* * Lookup a key sequence in an index. *) let rec find_list index keys = match keys with [] -> raise Not_found | key :: [] -> find index key | key :: keys -> let index = find_index index key in find_list index keys (* * Lookup the subindex for a key sequence. *) let find_list_index index keys = let index, _ = find_list index keys in index (* * Lookup the data for a key sequence. *) let find_list_data index keys = let _, data = find_list index keys in data (* * Lookup subindex and data for a key, return an option. *) let find_opt index key = try Some (find index key) with Not_found -> None (* * Lookup subindex for a key, return an option. *) let find_index_opt index key = try Some (find_index index key) with Not_found -> None (* * Lookup data for key, return an option (Some data or None). *) let find_data_opt index key = try Some (find_data index key) with Not_found -> None (* * Filter add a (key, (index, data)) pair to an index. *) let filter_add_i index key f = match index with Leaf -> Index (EltTable.add (EltTable.empty) key (f None)) | Index table -> let i_entry = find_opt index key in Index (EltTable.add table key (f i_entry)) (* * Filter add a (key, data) pair to an index. *) let filter_add index key f = filter_add_i index key ( fun i_entry -> match i_entry with None -> Leaf, f None | Some (i, d) -> i, f (Some d) ) (* * Filter remove a key from an index using its (index, data) entry *) let filter_remove_i index key f = match index with Leaf -> Leaf | Index table -> let i_entry = f (find index key) in match i_entry with Some _ -> Index (EltTable.remove table key) | None -> index (* * Filter remove a key from an index using its data. *) let filter_remove index key f = filter_remove_i index key ( fun (i, d) -> match (f d) with Some d -> Some (i, d) | None -> None ) (* * Filter add a chain of (key, (index, data)) pairs to an index. *) let rec filter_add_list_i index keys fs = match keys, fs with [], [] -> index | key :: [], f :: [] -> filter_add_i index key f | key :: keys, f :: fs -> let index = filter_add_i index key f in let subindex, data = find index key in let subindex = filter_add_list_i subindex keys fs in filter_add_i index key (fun _ -> subindex, data) | _ -> raise (Invalid_argument "filter_add_list_i") (* * Filter add a chain of (key, data) pairs to an index. *) let rec filter_add_list index keys fs = match keys, fs with [], [] -> index | key :: [], f :: [] -> filter_add index key f | key :: keys, f :: fs -> let index = filter_add index key f in let subindex, data = find index key in let subindex = filter_add_list subindex keys fs in filter_add_i index key (fun _ -> subindex, data) | _ -> raise (Invalid_argument "filter_add_list") (* * Filter add an (index, data) entry at the end of a chain in the index. *) let rec filter_add_entry_i index keys f = match keys with [] -> index | key :: [] -> filter_add_i index key f | key :: keys -> let subindex, data = find index key in let subindex = filter_add_entry_i subindex keys f in filter_add_i index key (fun _ -> subindex, data) (* * Filter add a data entry at the end of a chain in the index. *) let filter_add_entry index keys f = filter_add_entry_i index keys ( fun i_entry -> match i_entry with None -> Leaf, f None | Some (i, d) -> i, f (Some d) ) (* * Filter remove an (index, data) entry at the end of a chain in the index. *) let rec filter_remove_entry_i index keys f = match keys with [] -> index | key :: [] -> filter_remove_i index key f | key :: keys -> let subindex, data = find index key in let subindex = filter_remove_entry_i subindex keys f in filter_add_i index key (fun _ -> subindex, data) (* * Filter remove a data entry at the end of a chain in the index. *) let filter_remove_entry index keys f = filter_remove_entry_i index keys ( fun (i, d) -> match (f d) with Some d -> Some (i, d) | None -> None ) (* * Add a (key, data) pair to an index. *) let add index key data = filter_add index key (fun _ -> data) (* * Add a (key, (index, data)) pair to an index. *) let add_i index key i_entry = filter_add_i index key (fun _ -> i_entry) (* * Remove a key from an index. *) let remove index key = filter_remove index key (fun data -> Some data) (* * Add a chain of (key, data) pairs to an index. *) let add_list index keys datas = let fs = List.map (fun data -> (fun _ -> data)) datas in filter_add_list index keys fs (* * Add a chain of (key, (index, data)) pairs to an index. *) let add_list_i index keys i_entries = let fs = List.map (fun i_entry -> (fun _ -> i_entry)) i_entries in filter_add_list_i index keys fs (* * Add a data entry at the end of a chain in the index. *) let add_entry index keys data = filter_add_entry index keys (fun _ -> data) (* * Add an (index, data) entry at the end of a chain in the index. *) let add_entry_i index keys i_entry = filter_add_entry_i index keys (fun _ -> i_entry) (* * Remove an entry at the end of a chain in the index. *) let remove_entry index keys = filter_remove_entry index keys (fun data -> Some data) (* * Iterate over the top level entries. *) let iter f = function Leaf -> () | Index table -> EltTable.iter f table (* * Apply map to the top level entries. *) let map f = function Leaf -> Leaf | Index table -> Index (EltTable.map f table) (* * Apply map to top level entries using keys. *) let mapi f = function Leaf -> Leaf | Index table -> Index (EltTable.mapi f table) (* * Fold over top level entries. *) let fold f data = function Leaf -> data | Index table -> EltTable.fold f data table (* * Fold map over top level entries. *) let fold_map f data = function Leaf -> data, Leaf | Index table -> let data', table' = EltTable.fold_map f data table in data', Index (table') (* * Iterate over every entry in the index. *) let rec iter_all_list f keys = function Leaf -> () | Index table -> EltTable.iter ( fun key (index, data) -> let keys = keys @ [key] in f keys data; iter_all_list f keys index ) table let iter_all f index = iter_all_list f [] index (* * Apply map to every element in the index. *) let rec map_all f = function Leaf -> Leaf | Index table -> Index ( EltTable.map ( fun (index, data) -> (map_all f index, f data) ) table ) (* * Apply map using keys. *) let rec mapi_all_list f keys = function Leaf -> Leaf | Index table -> Index ( EltTable.mapi ( fun key (index, data) -> let keys = keys @ [key] in (mapi_all_list f keys index, f keys data) ) table ) let mapi_all f index = mapi_all_list f [] index (* * Fold over the index. *) let rec fold_all_list f keys data = function Leaf -> data | Index table -> EltTable.fold ( fun a key (index, b) -> let keys = keys @ [key] in (fold_all_list f keys (f a keys b) index) ) data table let fold_all f data index = fold_all_list f [] data index (* * Fold map over the index. *) let rec fold_map_all_list f keys data = function Leaf -> data, Leaf | Index table -> let data', table' = EltTable.fold_map ( fun a key (index, b) -> let keys = keys @ [key] in let res_a, res_c = f a keys b in let res_a', index' = fold_map_all_list f keys res_a index in res_a', (index', res_c) ) data table in data', Index (table') let fold_map_all f data index = fold_map_all_list f [] data index end