struct
  type 'a t = ('a, Biocaml_iset.t) Map.Poly.t

  let inter u v =
    Map.fold u ~init:Map.Poly.empty ~f:(fun ~key:k ~data:set_u accu ->
      match Map.find v k with
      | Some set_v -> Map.Poly.add accu ~key:k ~data:(Biocaml_iset.inter set_u set_v)
      | None -> accu
    )

  let union u v =
    Map.fold u ~init:Map.Poly.empty ~f:(fun ~key:k ~data:set_u accu ->
      match Map.find v k with
      | Some set_v -> Map.Poly.add accu ~key:k ~data:(Biocaml_iset.union set_u set_v)
      | None -> accu
    )

  let diff u v =
    Map.fold u ~init:Map.Poly.empty ~f:(fun ~key:k ~data:set_u accu ->
      let set_u' =
        match Map.find v k with
        | Some set_v -> Biocaml_iset.diff set_u set_v
        | None -> set_u
      in 
      Map.Poly.add ~key:k ~data:set_u' accu
    )

  let size x =
    Map.fold x ~init:0 ~f:(fun ~key ~data:set accu -> Biocaml_iset.cardinal set + accu)

  let intersection_size (k,r) dom = Biocaml_iset.(
    match Map.find dom k with
    | Some x -> 
      inter Range.(add_range empty r.lo r.hi) x
      |! cardinal
    | None -> 0
  )

  let intersects (k,r) dom =
    Option.value_map
      (Map.find dom k)
      ~default:false
      ~f:(fun x -> Range.(Biocaml_iset.intersects_range x r.lo r.hi))
      
  let to_stream dom =
    (Map.to_stream dom) 
    /@ (fun (k,s) -> Stream.map ~f:(fun (lo,hi) -> k, Range.make lo hi) (Biocaml_iset.to_stream s))
      |! Stream.concat

  let of_stream e =
    let accu = Accu.create Biocaml_iset.empty fst (fun (_,r) -> Range.(fun x -> Biocaml_iset.add_range x r.lo r.hi)) in
    Stream.iter ~f:(fun loc -> Accu.add accu loc loc ) e ;
    Map.of_stream (Accu.stream accu)
end