+(* pointer *)
+
+let string_of_pointer p =
+ let map = function
+ | ET.One i -> string_of_int i
+ | ET.Many is -> String.concat "," (List.map string_of_int is)
+ in
+ String.concat "." (List.map map p)
+
+let pointer_of_string s =
+ let map s =
+ match list_map_filter int_of_string_opt [] (String.split_on_char ',' s) with
+ | [] -> None
+ | [i] -> Some (ET.One i)
+ | is -> Some (ET.Many is)
+ in
+ list_map_filter map [] (String.split_on_char '.' s)
+
+let rec pointer_visit f l = function
+ | [] -> f (List.rev l)
+ | ET.One i :: tl -> pointer_visit f (i::l) tl
+ | ET.Many is :: tl ->
+ let map i = pointer_visit f (i::l) tl in
+ List.iter map is
+
+let list_visit before each visit after selected key_of string_of p l =
+ let ptr p = string_of_pointer (List.rev p) in
+ let rec aux i = function
+ | [] -> ()
+ | x :: tl ->
+ let q = ET.One i :: p in
+ each (ptr p) (ptr q) (selected x) (key_of x) (string_of_int i) (string_of x);
+ visit q x;
+ aux (succ i) tl
+ in
+ let s, c = list_count selected 0 0 l in
+ let count = Printf.sprintf "%u/%u" s c in
+ before (ptr p) count;
+ aux 0 l;
+ after ()
+
+(* error *)