Section AdAlloc.
Variable A : Set.
(** Allocator: returns an address not in the domain of [m]. This allocator is optimal in that it returns the lowest possible address, in the usual ordering on integers. It is not the most efficient, however. *)
Fixpoint ad_alloc_opt (m:Map A) : ad :=
match m with
| M0 => N0
| M1 a _ => if N.eqb a N0 then Npos 1 else N0
| M2 m1 m2 =>
N.min (N.double (ad_alloc_opt m1))
(Ndouble_plus_one (ad_alloc_opt m2))
end.
(** Moreover, this is optimal: all addresses below [(ad_alloc_opt m)] are in [dom m]: *)

Lemma ad_alloc_opt_optimal_1 :
forall (m:Map A) (a:ad),
Nleb (ad_alloc_opt m) a = false -> {y : A | MapGet A m a = Some y}.